{"record":{"id":"9e126f2b719e3852","repo":"oven-sh/bun","slug":"bad","errorCode":null,"errorMessage":"bad","messagePattern":"bad","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"bench/snippets/module-exports-putter.cjs","lineNumber":10,"sourceCode":"// This is a stress test of some internals in How Bun does the module.exports assignment.\n// If it crashes or throws then this fails\nimport(\"../runner.mjs\").then(({ bench, run }) => {\n  bench(\"Object.defineProperty(module, 'exports', { get() { return 42; } })\", () => {\n    Object.defineProperty(module, \"exports\", {\n      get() {\n        return 42;\n      },\n      set() {\n        throw new Error(\"bad\");\n      },\n      configurable: true,\n    });\n    if (module.exports !== 42) throw new Error(\"bad\");\n    if (!Object.getOwnPropertyDescriptor(module, \"exports\").get) throw new Error(\"bad\");\n  });\n\n  bench(\"Object.defineProperty(module.exports = {})\", () => {\n    Object.defineProperty(module, \"exports\", {\n      value: { abc: 123 },\n    });\n\n    if (!module.exports.abc) throw new Error(\"bad\");\n    if (Object.getOwnPropertyDescriptor(module, \"exports\").value !== module.exports) throw new Error(\"bad\");\n  });\n\n  bench(\"module.exports = {}\", () => {\n    module.exports = { abc: 123 };","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/bench/snippets/module-exports-putter.cjs#L1-L28","documentation":"Stress test of Bun's module.exports handling in CommonJS. This particular throw lives inside a setter deliberately installed via Object.defineProperty(module, 'exports', { get() { return 42; }, set() { throw new Error('bad'); } }). Its purpose is to prove that defining — and later reading — module.exports never performs a plain assignment through the property. The error fires only if the runtime actually invokes the setter, i.e. something assigned to module.exports and triggered the user-visible [[Set]] instead of defining the property.","triggerScenarios":"Object.defineProperty on `module` with an accessor pair whose setter throws, followed by any code path (module wrapper, transpiled output, engine internals) that does `module.exports = value` instead of Object.defineProperty — the assignment calls the poisoned setter.","commonSituations":"Regressions in Bun's CJS module wrapper / exports putter that fall back to assignment; transpilers or bundlers emitting `module.exports = ...` after user code installs an accessor; comparing Bun against Node where Node never calls the setter during defineProperty.","solutions":["Minimize to a single .cjs file: install the accessor, then only read module.exports and the descriptor; if it throws, the runtime invoked the setter","Run the same file under Node to confirm the expected (non-throwing) behavior","If Bun-only, report to oven-sh/bun with the minimized file — the module.exports define path is doing an assignment"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// prove the setter is never invoked when defining/reading module.exports\nlet setterCalled = false;\nObject.defineProperty(module, 'exports', {\n  get() { return 42; },\n  set() { setterCalled = true; },\n  configurable: true,\n});\nvoid module.exports;\nif (setterCalled) throw new Error('runtime invoked the module.exports setter during define/read');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In application code, prefer plain `module.exports = value` — accessor tricks on module.exports are edge-case territory even on Node","Add conformance tests that define poisoned setters on module.exports when changing CJS wrapper code in Bun","Compare any exotic module.exports behavior against Node first to know which runtime is wrong"],"tags":["commonjs","module-exports","benchmark","assertion"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}