{"record":{"id":"4c5483e07ea8368b","repo":"swc-project/swc","slug":"name-is-read-only","errorCode":null,"errorMessage":"\"${name}\" is read-only","messagePattern":"\"(.+?)\" is read-only","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/swc_ecma_transforms_base/src/helpers/generated/_read_only_error.rs","lineNumber":11,"sourceCode":"// This file is generated by `cargo codegen helpers`. DO NOT MODIFY.\n\nuse super::{HelperDef, HelperName};\n\npub const DEF: HelperDef = HelperDef {\n    name: HelperName::read_only_error,\n    local: \"_read_only_error\",\n    import_path: \"@swc/helpers/_/_read_only_error\",\n    #[cfg(feature = \"inline-helpers\")]\n    source: r#\"function _read_only_error(name) {\n    throw new TypeError(\"\\\"\" + name + \"\\\" is read-only\");\n}\n\"#,\n    #[cfg(feature = \"inline-helpers\")]\n    deps: super::HelperBitmap::from_bits(0x00000000000008000000000000000000),\n};\n\n#[cfg(feature = \"inline-helpers\")]\npub fn stmts() -> &'static [swc_ecma_ast::Stmt] {\n    static STMTS: once_cell::sync::Lazy<Vec<swc_ecma_ast::Stmt>> =\n        once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path));\n    &STMTS\n}\n","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_ecma_transforms_base/src/helpers/generated/_read_only_error.rs#L1-L24","documentation":"SWC's ES2022 class-properties transform lowers private accessors; when the transform sees an assignment to a private accessor that declares only a getter, it emits `_read_only_error(\"#x\")` (crates/swc_ecma_compat_es2022/src/class_properties/private_field.rs:367). At runtime the helper throws `TypeError: \"#x\" is read-only`, matching the TypeError engines produce for writing a get-only private accessor.","triggerScenarios":"`class A { get #x() { return this._x; } write(v) { this.#x = v; } }` — any assignment (`this.#x = ...`, compound assigns, `++`) to a get-only private accessor in code downleveled by the class-properties pass.","commonSituations":"Declaring intent as read-only via a getter-only private accessor and later adding a mutation path that forgets to add the setter; refactoring a public getter to `#private` while call sites still write; code generators emitting writes to computed private accessors.","solutions":["Add a matching private setter: `set #x(v) { this._x = v; }`.","Store state in a plain private field (`#x`) and expose a getter, mutating the field directly instead of the accessor.","Remove the assignment; the design is read-only, so move the mutation inside the class where the backing field lives."],"exampleFix":"// before\nclass Counter {\n  get #value() { return this._v; }\n  increment() { this.#value = this.#value + 1; } // TypeError: \"#value\" is read-only\n}\n\n// after\nclass Counter {\n  #value = 0;\n  get value() { return this.#value; }\n  increment() { this.#value += 1; }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Private accessors cannot be reflectively inspected, so guard the mutation site.\ntry {\n  this.#value = next;\n} catch (err) {\n  if (err instanceof TypeError && /is read-only/.test(err.message)) {\n    // accessor has no setter — route through the mutation API instead\n    this.writeInternal(next);\n  } else throw err;\n}","preventionTips":["Declare accessor pairs together (`get #x()` with `set #x()`) or skip accessors entirely and use a plain private field `#x`.","Lint against assignments to getter-only members (TS emits error TS2540 for the native case; keep the same discipline for `#private`).","When a value is read-only by design, expose mutation only through named methods so no call site ever assigns."],"tags":["private-field","accessor","readonly","es2022","class-properties"],"backgroundTag":"read-from-write-only-property","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}