diff --git a/src/jsc/bindings/FormatStackTraceForJS.cpp b/src/jsc/bindings/FormatStackTraceForJS.cpp index 9cbaf3b2909d..cca4900cb3d3 100644 --- a/src/jsc/bindings/FormatStackTraceForJS.cpp +++ b/src/jsc/bindings/FormatStackTraceForJS.cpp @@ -647,6 +647,10 @@ JSC::JSValue computeErrorInfoWrapperToJSValue(JSC::VM& vm, Vector& s line_in = line.oneBasedInt(); column_in = column.oneBasedInt(); + // materializeErrorInfoIfNeeded putDirect()s this unconditionally; an empty JSValue + // in property storage crashes the next read. https://github.com/oven-sh/bun/issues/34095 + if (!result) [[unlikely]] + return jsUndefined(); return result; } diff --git a/test/js/node/v8/capture-stack-trace.test.js b/test/js/node/v8/capture-stack-trace.test.js index 20d405594b28..a834a4b0a0ad 100644 --- a/test/js/node/v8/capture-stack-trace.test.js +++ b/test/js/node/v8/capture-stack-trace.test.js @@ -1003,3 +1003,27 @@ test("printing an error whose message getter calls Error.captureStackTrace on it expect({ lastLine: stdout.trimEnd().split("\n").pop(), exitCode }).toEqual({ lastLine: "after", exitCode: 0 }); }); + +// https://github.com/oven-sh/bun/issues/34095 +test("lazy error-info materialization does not store an empty stack value when the compute hook throws", async () => { + const src = ` + Error.prepareStackTrace = (e, s) => "custom-stack"; + const e = new Error("x"); + Object.defineProperty(e, "message", { get() { throw new TypeError("msg-boom"); } }); + let first = "no-throw"; + try { void e.stack; } catch (err) { first = err.message; } + console.log(JSON.stringify({ first, secondType: typeof e.stack })); + `; + await using proc = Bun.spawn({ + cmd: [bunExe(), "-e", src], + env: bunEnv, + stdout: "pipe", + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + expect({ stdout: stdout.trim(), signalCode: proc.signalCode }).toEqual({ + stdout: JSON.stringify({ first: "msg-boom", secondType: "undefined" }), + signalCode: null, + }); + expect(exitCode).toBe(0); +});