diff --git a/src/runtime/api/BunObject.rs b/src/runtime/api/BunObject.rs index cae8d6b8095c..b32b859f39a2 100644 --- a/src/runtime/api/BunObject.rs +++ b/src/runtime/api/BunObject.rs @@ -720,7 +720,14 @@ pub fn bun_inspect(global_this: &JSGlobalObject, value: JSValue) -> BunString { let mut array: Vec = Vec::new(); let mut formatter = ConsoleObject::Formatter::new(global_this); - if write!(&mut array, "{}", value.to_fmt(&mut formatter)).is_err() { + use core::fmt::Write; + if write!( + bun_core::fmt::VecWriter(&mut array), + "{}", + value.to_fmt(&mut formatter) + ) + .is_err() + { return BunString::empty(); } BunString::clone_utf8(&array) diff --git a/test/js/bun/cookie/cookie-expires-validation.test.ts b/test/js/bun/cookie/cookie-expires-validation.test.ts index abc84be72eed..defa7c92cc20 100644 --- a/test/js/bun/cookie/cookie-expires-validation.test.ts +++ b/test/js/bun/cookie/cookie-expires-validation.test.ts @@ -1,4 +1,5 @@ import { describe, expect, test } from "bun:test"; +import { bunEnv, bunExe } from "harness"; describe("Bun.Cookie expires validation", () => { describe("Date objects", () => { @@ -76,6 +77,36 @@ describe("Bun.Cookie expires validation", () => { }).toThrow(); }); + test("throws for objects whose inspect.custom throws", async () => { + // Bun__inspect renders the received value into the error message; a + // throwing inspect.custom must surface as a JS error, not a crash. + // Spawn a subprocess so a regression fails cleanly instead of aborting. + const src = ` + const obj = { + [Symbol.for("nodejs.util.inspect.custom")]() { + throw new Error("boom from inspect.custom"); + }, + }; + try { + new Bun.Cookie("name", "value", { expires: obj }); + console.log("no-throw"); + } catch (e) { + console.log("threw:" + e.message); + } + `; + 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(), stderr, exitCode }).toMatchObject({ + stdout: "threw:boom from inspect.custom", + exitCode: 0, + }); + }); + test("invalid strings throw", () => { expect(() => { new Bun.Cookie("name", "value", { expires: "tomorrow" });