{"record":{"id":"619c6bd4a4294717","repo":"oven-sh/bun","slug":"private-method-is-not-writable","errorCode":null,"errorMessage":"Private method is not writable","messagePattern":"Private method is not writable","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"bench/snippets/private.mjs","lineNumber":17,"sourceCode":"import { bench, run } from \"../runner.mjs\";\n// This is a benchmark of the performance impact of using private properties.\n\nbench(\"Polyfillprivate\", () => {\n  \"use strict\";\n  var __classPrivateFieldGet =\n    (this && this.__classPrivateFieldGet) ||\n    function (receiver, state, kind, f) {\n      if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n      if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n        throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n      return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n    };\n  var __classPrivateFieldSet =\n    (this && this.__classPrivateFieldSet) ||\n    function (receiver, state, value, kind, f) {\n      if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n      if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n      if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n        throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n      return kind === \"a\" ? f.call(receiver, value) : f ? (f.value = value) : state.set(receiver, value), value;\n    };\n  var _Foo_state, _Foo_inc;\n  class Foo {\n    constructor() {\n      _Foo_state.set(this, 1);\n      _Foo_inc.set(this, 13);\n    }\n    run() {\n      let n = 1000000;\n      while (n-- > 0) {\n        __classPrivateFieldSet(\n          this,\n          _Foo_state,\n          __classPrivateFieldGet(this, _Foo_state, \"f\") + __classPrivateFieldGet(this, _Foo_inc, \"f\"),","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/bench/snippets/private.mjs#L1-L35","documentation":"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.","triggerScenarios":"Downleveled TypeScript executing `this.#method = someFunction` (generated as __classPrivateFieldSet(..., 'm')), or hand-calling the polyfill with kind 'm' — both are unconditional throws.","commonSituations":"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.","solutions":["Remove the assignment to the private method — declare the behavior you need inside the class","If the member must be replaceable, make it a private field holding a function (#handler = () => {}) instead of a method","Add a dedicated setter method on the class that changes internal state instead of rewriting the method"],"exampleFix":"// before\nclass Foo {\n  #onDone() {}\n  reset() { this.#onDone = () => {}; } // TypeError: not writable\n}\n// after\nclass Foo {\n  #onDone = () => {};\n  reset() { this.#onDone = () => {}; }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  this.#handler = fn; // illegal if #handler is a method\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('Private method is not writable')) {\n    throw new TypeError('cannot replace private method; use a private field holding a function instead');\n  }\n  throw e;\n}","preventionTips":["Model replaceable behavior as a private field holding a function (#handler = () => {}), never as a private method","Search for assignments to #methods when refactoring fields into methods — the compiler catches native cases, downlevel code fails only at runtime","Keep hot-path classes on ES2022+ output so invalid writes surface at compile time"],"tags":["typescript","private-methods","assignment","downlevel-emit"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}