oven-sh/bun · error · Error

bad

Error message

bad

What it means

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.

Source

Thrown at bench/snippets/module-exports-putter.cjs:10

// This is a stress test of some internals in How Bun does the module.exports assignment.
// If it crashes or throws then this fails
import("../runner.mjs").then(({ bench, run }) => {
  bench("Object.defineProperty(module, 'exports', { get() { return 42; } })", () => {
    Object.defineProperty(module, "exports", {
      get() {
        return 42;
      },
      set() {
        throw new Error("bad");
      },
      configurable: true,
    });
    if (module.exports !== 42) throw new Error("bad");
    if (!Object.getOwnPropertyDescriptor(module, "exports").get) throw new Error("bad");
  });

  bench("Object.defineProperty(module.exports = {})", () => {
    Object.defineProperty(module, "exports", {
      value: { abc: 123 },
    });

    if (!module.exports.abc) throw new Error("bad");
    if (Object.getOwnPropertyDescriptor(module, "exports").value !== module.exports) throw new Error("bad");
  });

  bench("module.exports = {}", () => {
    module.exports = { abc: 123 };

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. 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
  2. Run the same file under Node to confirm the expected (non-throwing) behavior
  3. If Bun-only, report to oven-sh/bun with the minimized file — the module.exports define path is doing an assignment
Defensive patterns

Strategy: validation

Validate before calling

// prove the setter is never invoked when defining/reading module.exports
let setterCalled = false;
Object.defineProperty(module, 'exports', {
  get() { return 42; },
  set() { setterCalled = true; },
  configurable: true,
});
void module.exports;
if (setterCalled) throw new Error('runtime invoked the module.exports setter during define/read');

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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