microsoft/TypeScript · error · TypeError

Cannot read private member from an object whose class did no

Error message

Cannot read private member from an object whose class did not declare it

What it means

Runtime TypeError from `__classPrivateFieldGet`. After resolving accessor/method kind, the helper performs a brand check: for instance members it requires `state.has(receiver)` (a WeakMap/WeakSet hit), and for static members it requires `receiver === state` (the class constructor). If the receiver was not constructed by the declaring class (or is not the class itself for statics), the brand check fails and this is thrown.

Source

Thrown at src/compiler/factory/emitHelpers.ts:1288

 *
 * Reading from a private static get accessor (when defined, TS 4.3+):
 *      __classPrivateFieldGet(<any>, <constructor>, "a", <function>)
 *
 * Reading from a private static get accessor (when not defined, TS 4.3+):
 *      __classPrivateFieldGet(<any>, <constructor>, "a", void 0)
 *      NOTE: This always results in a runtime error.
 *
 * Reading from a private static method (TS 4.3+):
 *      __classPrivateFieldGet(<any>, <constructor>, "m", <function>)
 */
const classPrivateFieldGetHelper: UnscopedEmitHelper = {
    name: "typescript:classPrivateFieldGet",
    importName: "__classPrivateFieldGet",
    scoped: false,
    text: `
            var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
                if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
                if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
                return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
            };`,
};

/**
 * Parameters:
 *  @param receiver — The object on which the private member will be set.
 *  @param state — One of the following:
 *      - A WeakMap used to store a private instance field.
 *      - A WeakSet used as an instance brand for private instance methods and accessors.
 *      - A function value that should be the undecorated class constructor used to brand check private static fields, methods, and accessors.
 *  @param value — The value to set.
 *  @param kind — (optional pre TS 4.3, required for TS 4.3+) One of the following values:
 *       - undefined — Indicates a private instance field (pre TS 4.3).
 *       - "f" — Indicates a private field (instance or static).
 *       - "m" — Indicates a private method (instance or static).
 *       - "a" — Indicates a private accessor (instance or static).
 *   @param f — (optional pre TS 4.3) Depends on the arguments for state and kind:

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Make sure the receiver is a real instance produced by `new C()`.
  2. Type the parameter as the declaring class (`o: C`) so alien receivers are rejected at compile time.
  3. When deserializing, rehydrate into a class instance before invoking private-reading methods.
  4. For static private members, call on the class constructor itself, not a copy.

Example fix

// before
class C {
  #x = 1;
  static read(o: any) { return o.#x; }   // {} as any throws at runtime
}
C.read({} as any);
// after
class C {
  #x = 1;
  static read(o: C) { return o.#x; }     // typed receiver
  static isC(o: unknown): o is C { return o instanceof C; }
}
const c = new C();
C.read(c);
Defensive patterns

Strategy: validation

Validate before calling

// Validate the receiver was constructed by the class before touching privates:
function safeRead(o: unknown): number | undefined {
  return o instanceof C ? (o as C).#x : undefined;
}

Type guard

function isC(o: unknown): o is C { return o instanceof C; }

Prevention

When it happens

Trigger: Accessing a private instance member on an object that was not constructed by the declaring class (e.g. `C.prototype.method.call(alienObject)` where the method reads `this.#x`), or passing the wrong constructor for a private static member. Common via `as any` casts, `Object.create(C.prototype)`, or cross-class helper calls.

Common situations: Calling a method that reads a private field on an object obtained through `Object.create`, structural casts, or deserialization (`JSON.parse` produces plain objects with no branding); subclass/superclass wiring that bypasses constructors; static private access from a non-class receiver.

Related errors


AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12). Data as JSON: /api/errors/bad8fcb097571296. Report an issue: GitHub.