microsoft/TypeScript · error · TypeError
Cannot write private member to an object whose class did not
Error message
Cannot write private member to an object whose class did not declare it
What it means
Runtime TypeError from `__classPrivateFieldSet`, the write-path brand check. After the kind checks pass, the helper requires `state.has(receiver)` (instance) or `receiver === state` (static). If the receiver was not branded by the declaring class, the write is rejected. Mirror of error 21 on the write path.
Source
Thrown at src/compiler/factory/emitHelpers.ts:1352
* __classPrivateFieldSet(<any>, <constructor>, <any>, "a", <function>)
*
* Writing to a private static set accessor (when not defined, TS 4.3+):
* __classPrivateFieldSet(<any>, <constructor>, <any>, "a", void 0)
* NOTE: This always results in a runtime error.
*
* Writing to a private static method (TS 4.3+):
* __classPrivateFieldSet(<any>, <constructor>, <any>, "m", <function>)
* NOTE: This always results in a runtime error.
*/
const classPrivateFieldSetHelper: UnscopedEmitHelper = {
name: "typescript:classPrivateFieldSet",
importName: "__classPrivateFieldSet",
scoped: false,
text: `
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};`,
};
/**
* Parameters:
* @param state — One of the following:
* - A WeakMap when the member is a private instance field.
* - A WeakSet when the member is a private instance method or accessor.
* - A function value that should be the undecorated class constructor when the member is a private static field, method, or accessor.
* @param receiver — The object being checked if it has the private member.
*
* Usage:
* This helper is used to transform `#field in expression` to
* `__classPrivateFieldIn(<weakMap/weakSet/constructor>, expression)`
*/
const classPrivateFieldInHelper: UnscopedEmitHelper = {
name: "typescript:classPrivateFieldIn",
View on GitHub (pinned to b465fdbfe1)
Solutions
- Ensure the receiver is a genuine instance built by `new C()`.
- Type setter parameters as the declaring class so alien receivers fail at compile time.
- Rehydrate deserialized data into class instances before calling setters.
- For static privates, invoke on the class constructor itself.
Example fix
// before
class C {
#x = 0;
static set(o: any, v: number) { o.#x = v; } // alien object throws
}
C.set(Object.create(C.prototype), 9);
// after
class C {
#x = 0;
static set(o: C, v: number) { o.#x = v; }
}
const c = new C();
C.set(c, 9); Defensive patterns
Strategy: validation
Validate before calling
function safeSet(o: unknown, v: number) { if (o instanceof C) { (o as C).#x = v; } } Type guard
function isC(o: unknown): o is C { return o instanceof C; } Prevention
- Never feed plain/deserialized objects into private-member setters.
- Type all setter entry points as the declaring class, not `any`.
When it happens
Trigger: Assigning to a private member through a method invoked on an alien receiver (`C.prototype.setter.call(plainObj, v)`), or writing a static private member on something that is not the class constructor. Typically reached through `as any`, `Object.create`, or deserialized objects.
Common situations: Hydrating objects via `JSON.parse` and calling setters on them; proxy/subclass machinery that does not run the class constructor; cross-class helpers that accept `any`.
Related errors
- Cannot read private member from an object whose class did no
- Private accessor was defined without a getter
- Private method is not writable
- Private accessor was defined without a setter
- Cannot use 'in' operator on non-object
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/069a8d84a3433446.
Report an issue: GitHub.