oven-sh/bun · error · TypeError

Private method is not writable

Error message

Private method is not writable

What it means

The method guard in the TypeScript __classPrivateFieldSet polyfill: kind 'm' marks the private member as a method, and methods are never writable, so any attempted write throws immediately. It mirrors the native TypeError you get from `this.#method = fn`. In private.mjs the guard is part of the downlevel polyfill being benchmarked; the Foo class only uses kind 'f', so this fires only if something assigns to a private method.

Source

Thrown at bench/snippets/private.mjs:17

import { bench, run } from "../runner.mjs";
// This is a benchmark of the performance impact of using private properties.

bench("Polyfillprivate", () => {
  "use strict";
  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);
    };
  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;
    };
  var _Foo_state, _Foo_inc;
  class Foo {
    constructor() {
      _Foo_state.set(this, 1);
      _Foo_inc.set(this, 13);
    }
    run() {
      let n = 1000000;
      while (n-- > 0) {
        __classPrivateFieldSet(
          this,
          _Foo_state,
          __classPrivateFieldGet(this, _Foo_state, "f") + __classPrivateFieldGet(this, _Foo_inc, "f"),

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Remove the assignment to the private method — declare the behavior you need inside the class
  2. If the member must be replaceable, make it a private field holding a function (#handler = () => {}) instead of a method
  3. Add a dedicated setter method on the class that changes internal state instead of rewriting the method

Example fix

// before
class Foo {
  #onDone() {}
  reset() { this.#onDone = () => {}; } // TypeError: not writable
}
// after
class Foo {
  #onDone = () => {};
  reset() { this.#onDone = () => {}; }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  this.#handler = fn; // illegal if #handler is a method
} catch (e) {
  if (e instanceof TypeError && e.message.includes('Private method is not writable')) {
    throw new TypeError('cannot replace private method; use a private field holding a function instead');
  }
  throw e;
}

Prevention

When it happens

Trigger: Downleveled TypeScript executing `this.#method = someFunction` (generated as __classPrivateFieldSet(..., 'm')), or hand-calling the polyfill with kind 'm' — both are unconditional throws.

Common situations: Attempting to monkey-patch or swap behavior by overwriting a private method; refactoring a private field holding a function into a method without updating assignments; code ported from public-method patterns.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/619c6bd4a4294717. Report an issue: GitHub.