Skip to content

lib: brand-check Navigator getters to throw ERR_INVALID_THIS#63601

Open
3zrv wants to merge 1 commit into
nodejs:mainfrom
3zrv:fix/navigator-getters-throws
Open

lib: brand-check Navigator getters to throw ERR_INVALID_THIS#63601
3zrv wants to merge 1 commit into
nodejs:mainfrom
3zrv:fix/navigator-getters-throws

Conversation

@3zrv
Copy link
Copy Markdown
Contributor

@3zrv 3zrv commented May 27, 2026

Fixes: #63513

Add an explicit #field in this brand check to each getter so a proper ERR_INVALID_THIS is thrown, matching browser behavior. This also fixes language, which previously did not error at all on the prototype because it did not touch a private field.

Fixes: nodejs#63513

Signed-off-by: Mohamed Sayed <k@3zrv.com>
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/web-standards

@nodejs-github-bot nodejs-github-bot added the needs-ci PRs that need a full CI run. label May 27, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.32%. Comparing base (2cdea86) to head (a8d88e8).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #63601   +/-   ##
=======================================
  Coverage   90.32%   90.32%           
=======================================
  Files         730      730           
  Lines      234669   234680   +11     
  Branches    43946    43965   +19     
=======================================
+ Hits       211967   211985   +18     
  Misses      14417    14417           
+ Partials     8285     8278    -7     
Files with missing lines Coverage Δ
lib/internal/navigator.js 99.40% <100.00%> (+0.03%) ⬆️

... and 27 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aduh95
Copy link
Copy Markdown
Contributor

aduh95 commented May 27, 2026

I don't think adding a check is worth it, I think the current behavior is fine actually, the spec requires a TypeError, we're throwing a TypeError (except for .language, indeed that's worth fixing). For reference, Chromium-based browsers throw TypeError: Illegal invocation

Copy link
Copy Markdown
Member

@LiviaMedeiros LiviaMedeiros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on explicit ERR_INVALID_THIS over implicit private field access. Errors from private fields are misleading and not future-proof: it's too easy to break 'implicit throw' unintentionally (in fact, Navigator.prototype.language was initially introduced using private field, too).

@aduh95
Copy link
Copy Markdown
Contributor

aduh95 commented May 27, 2026

Errors from private fields are misleading and not future-proof: it's too easy to break 'implicit throw' unintentionally

It’s only true if that’s not covered by tests (which I would have expected WPT to cover, but I guess not, or at least not the subset we’re running)

Copy link
Copy Markdown
Member

@KhafraDev KhafraDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In undici we are lenient with errors too with the expectation that a reviewer would notice if a change similar to the one that changed .language was made.

Since it's not reasonable here, I think the change is fine. Regarding the WPTs, brand checks should be implemented the same across globals in most platforms so the assumption is that if you have it implemented properly in one spec, it's also implemented correctly in the thousands of over browser globals.

Comment on lines +153 to +161
const getterNames = [
'hardwareConcurrency',
'locks',
'language',
'languages',
'userAgent',
'platform',
];
for (const name of getterNames) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const getterNames = [
'hardwareConcurrency',
'locks',
'language',
'languages',
'userAgent',
'platform',
];
for (const name of getterNames) {
for (const name of Object.keys(Navigator.prototype)) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected error "Cannot read private member #availableParallelism from an object whose class did not declare it"

5 participants