Contact me →

node.js syntax checker bug about shadowing in private fields

Finally understood an issue I was encountering, that in my opinion is a bug and super confusing and deceptive.

SyntaxError: Private field must be declared in an enclosing class

The gist is the following: let's say you declared a class and have a private field (#somePrivateMethod) there.

class Example {
    #somePrivateMethod(param1) {}
}

node --check reports 👌 so all good so far.

The issue arises when you write a very specific typo inside #somePrivateMethod, namely shadowing the private method parameters.

e.g.

class Example {
    someInstanceMethod () {
        this.#somePrivateMethod('test')
    }
    #somePrivateMethod(param1) {
        // unintentional shadowing through typo or clanker
        const param1 = '...'
    }
}

node --check now will report the following:

tmp.js:3
        this.#somePrivateMethod('test')
            ^

SyntaxError: Private field '#somePrivateMethod' must be declared in an enclosing class
    at wrapSafe (node:internal/modules/cjs/loader:1806:18)
    at checkSyntax (node:internal/main/check_syntax:76:3)

Node.js v26.3.0

The bug caused the Node.js parser to lose track of the definition of the private field #somePrivateMethod and breaking its syntax checker.

To fix it, just do not inadvertently shadow/redeclare vars with the same name as the function arguments:

class Example {
    someInstanceMethod () {
        this.#somePrivateMethod('test')
    }
    #somePrivateMethod(param1) {
        // no shadowing/redeclaration
        const renamed = '...'
    }
}

This is extremely confusing, because it should be SyntaxError: Identifier 'param1' has already been declared.

Noticed that this only happens for #private methods.


Interestingly, the parser reports the error correctly, if the private method is not called!

class Example {
    #somePrivateMethod(param1) {
        const param1 = '...'
    }
}
tmp.js:3
        const param1 = '...'
              ^

SyntaxError: Identifier 'param1' has already been declared
    at wrapSafe (node:internal/modules/cjs/loader:1806:18)
    at checkSyntax (node:internal/main/check_syntax:76:3)

Node.js v26.3.0

This would have been the expected reporting.