-
Notifications
You must be signed in to change notification settings - Fork 3.8k
fix(bindings): handle pending exceptions in ReadableStream__empty and ReadableStream__used #25215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
… ReadableStream__used When accessing Response.json().body after catching a stack overflow exception, the pending exception state was not being properly handled in the C++ bindings. This caused a debug assertion failure: "Unexpected exception observed". The fix adds proper exception handling using DECLARE_THROW_SCOPE and RETURN_IF_EXCEPTION to both ReadableStream__empty and ReadableStream__used functions. Fixes: ENG-23921 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
WalkthroughAdds explicit exception handling in ReadableStream creation routines by introducing throw scopes and exception checks. Previously uncaught exceptions during ReadableStream.create could cause crashes. A regression test validates that accessing Response.json().body after a stack overflow does not crash. Changes
Possibly related PRs
Suggested reviewers
Pre-merge checks✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/bun.js/bindings/bindings.cpp(1 hunks)test/regression/issue/response-body-crash-after-stack-overflow.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
test/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)
test/**/*.{js,ts,jsx,tsx}: Write tests as JavaScript and TypeScript files using Jest-style APIs (test,describe,expect) and import frombun:test
Usetest.eachand data-driven tests to reduce boilerplate when testing multiple similar cases
Files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
test/regression/issue/**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
When a test is for a specific numbered GitHub Issue, place it in
test/regression/issue/${issueNumber}.test.tswith a REAL issue number, not a placeholder
Files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: For single-file tests, prefer using-eflag overtempDir
For multi-file tests, prefer usingtempDirfromharnessandBun.spawnover other temporary directory creation methods
Always useport: 0for network tests and do not hardcode ports or use custom random port number functions
UsenormalizeBunSnapshotto normalize snapshot output of tests
Never write tests that check for no 'panic' or 'uncaught exception' or similar in the test output - that is NOT a valid test
UsetempDirfromharnessto create temporary directories, do not usetmpdirSyncorfs.mkdtempSync
When spawning processes in tests, check stdout/stderr expectations BEFORE checking exit code to get more useful error messages on test failure
Do not write flaky tests - do not usesetTimeoutin tests, insteadawaitthe condition to be met as you are testing the CONDITION not the TIME PASSING
Verify your test fails withUSE_SYSTEM_BUN=1 bun test <file>and passes withbun bd test <file>- your test is NOT VALID if it passes withUSE_SYSTEM_BUN=1
Files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}
📄 CodeRabbit inference engine (test/CLAUDE.md)
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Usebun:testwith files that end in*.test.{ts,js,jsx,tsx,mjs,cjs}
Do not write flaky tests. Never wait for time to pass in tests; always wait for the condition to be met instead of using an arbitrary amount of time
Never use hardcoded port numbers in tests. Always useport: 0to get a random port
Prefer concurrent tests over sequential tests usingtest.concurrentordescribe.concurrentwhen multiple tests spawn processes or write files, unless it's very difficult to make them concurrent
When spawning Bun processes in tests, usebunExeandbunEnvfromharnessto ensure the same build of Bun is used and debug logging is silenced
Use-eflag for single-file tests when spawning Bun processes
UsetempDir()from harness to create temporary directories with files for multi-file tests instead of creating files manually
Prefer async/await over callbacks in tests
When callbacks must be used and it's just a single callback, usePromise.withResolversto create a promise that can be resolved or rejected from a callback
Do not set a timeout on tests. Bun already has timeouts
UseBuffer.alloc(count, fill).toString()instead of'A'.repeat(count)to create repetitive strings in tests, as ''.repeat is very slow in debug JavaScriptCore builds
Usedescribeblocks for grouping related tests
Always useawait usingorusingto ensure proper resource cleanup in tests for APIs like Bun.listen, Bun.connect, Bun.spawn, Bun.serve, etc
Always check exit codes and test error scenarios in error tests
Usedescribe.each()for parameterized tests
UsetoMatchSnapshot()for snapshot testing
UsebeforeAll(),afterEach(),beforeEach()for setup/teardown in tests
Track resources (servers, clients) in arrays for cleanup inafterEach()
Files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
test/regression/issue/**/*.test.ts
📄 CodeRabbit inference engine (test/CLAUDE.md)
Regression tests for specific issues go in
/test/regression/issue/${issueNumber}.test.ts. Do not put tests without issue numbers in the regression directory
Files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
src/**/*.{cpp,zig}
📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)
src/**/*.{cpp,zig}: Usebun bdorbun run build:debugto build debug versions for C++ and Zig source files; creates debug build at./build/debug/bun-debug
Run tests usingbun bd test <test-file>with the debug build; never usebun testdirectly as it will not include your changes
Execute files usingbun bd <file> <...args>; never usebun <file>directly as it will not include your changes
Enable debug logs for specific scopes usingBUN_DEBUG_$(SCOPE)=1environment variable
Code generation happens automatically as part of the build process; no manual code generation commands are required
Files:
src/bun.js/bindings/bindings.cpp
src/bun.js/bindings/**/*.cpp
📄 CodeRabbit inference engine (CLAUDE.md)
src/bun.js/bindings/**/*.cpp: C++ code for JavaScriptCore bindings and Web APIs should be placed insrc/bun.js/bindings/*.cpp
When implementing JavaScript classes in C++, create three classes if there's a public constructor:class Foo : public JSC::JSDestructibleObject,class FooPrototype : public JSC::JSNonFinalObject, andclass FooConstructor : public JSC::InternalFunction
When implementing JavaScript classes in C++, define properties using HashTableValue arrays and add iso subspaces for classes with C++ fields, caching structures in ZigGlobalObject
Files:
src/bun.js/bindings/bindings.cpp
src/**/*.{ts,zig,cpp}
📄 CodeRabbit inference engine (CLAUDE.md)
Always use absolute paths in file operations
Files:
src/bun.js/bindings/bindings.cpp
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 22946
File: test/js/sql/sql.test.ts:195-202
Timestamp: 2025-09-25T22:07:13.851Z
Learning: PR oven-sh/bun#22946: JSON/JSONB result parsing updates (e.g., returning parsed arrays instead of legacy strings) are out of scope for this PR; tests keep current expectations with a TODO. Handle parsing fixes in a separate PR.
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.tssrc/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:35:08.612Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/dev-server-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:08.612Z
Learning: Applies to test/bake/dev/bundle.test.ts : Organize bundle tests in bundle.test.ts for tests concerning bundling bugs that only occur in DevServer
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to test/js/bun/**/*.test.{ts,tsx} : For Bun-specific API tests, use the `test/js/bun/` directory (for http, crypto, ffi, shell, etc.)
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/regression/issue/**/*.test.ts : Regression tests for specific issues go in `/test/regression/issue/${issueNumber}.test.ts`. Do not put tests without issue numbers in the regression directory
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-03T20:40:59.655Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:35:39.205Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Add tests for new Bun runtime functionality
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to **/*.test.{ts,tsx} : Never write tests that check for no 'panic' or 'uncaught exception' or similar in the test output - that is NOT a valid test
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Always use `await using` or `using` to ensure proper resource cleanup in tests for APIs like Bun.listen, Bun.connect, Bun.spawn, Bun.serve, etc
Applied to files:
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use isolate->currentHandleScope()->createLocal<T>() to create local V8 handles and ensure all V8 values are created within an active handle scope
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Create V8 class implementations with .cpp extension following the pattern V8ClassName.cpp that include the header, v8_compatibility_assertions.h, use ASSERT_V8_TYPE_LAYOUT_MATCHES macro, and implement methods using isolate->currentHandleScope()->createLocal<T>() for handle creation
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:39.205Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Applies to **/js_*.zig : Use `bun.JSError!JSValue` for proper error propagation in JavaScript bindings
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : To create JavaScript objects from Zig, implement C++ functions following the `Bun__ClassName__toJS(Zig::GlobalObject*, NativeType*)` convention that construct and return the JavaScript object as an encoded JSValue
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Use `bun.JSError!JSValue` return type for Zig methods and constructors to enable proper error handling and exception propagation
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : Implement getter functions using `JSC_DEFINE_CUSTOM_GETTER` macro, performing type checking with `jsDynamicCast`, throwing errors for type mismatches, and returning encoded JSValue
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : When constructing JavaScript objects, retrieve the structure from the global object using `zigGlobalObject->m_JSX509CertificateClassStructure.get(zigGlobalObject)` or similar pattern
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : Implement function definitions using `JSC_DEFINE_HOST_FUNCTION` macro, performing type checking with `jsDynamicCast`, throwing this-type errors when type checking fails, and returning encoded JSValue
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Implement getter functions with naming pattern `get<PropertyName>` in Zig that accept `this` and `globalObject` parameters and return `JSC.JSValue`
Applied to files:
src/bun.js/bindings/bindings.cpp
🧬 Code graph analysis (2)
test/regression/issue/response-body-crash-after-stack-overflow.test.ts (1)
packages/bun-inspector-protocol/src/protocol/jsc/index.d.ts (1)
Response(2793-2806)
src/bun.js/bindings/bindings.cpp (3)
src/bun.js/bindings/JSBuffer.cpp (2)
call(320-336)call(320-320)src/bun.js/bindings/webcore/JSEventEmitter.cpp (2)
call(128-157)call(128-128)src/bun.js/bindings/ProcessBindingTTYWrap.cpp (1)
call(407-414)
🔇 Additional comments (1)
src/bun.js/bindings/bindings.cpp (1)
2919-2939: ReadableStream helpers now correctly guard JS calls with ThrowScopeWrapping the
JSC::callinReadableStream__empty/ReadableStream__usedwithDECLARE_THROW_SCOPEandRETURN_IF_EXCEPTIONis consistent with other bindings and should prevent leaving a pending exception on the VM when these helpers return. This directly addresses the “unexpected exception observed” assertion for theReadableStream.createpath.No further changes needed here.
| import { test } from "bun:test"; | ||
|
|
||
| // Fixes: ENG-23921 | ||
| // Accessing Response.json().body after catching a stack overflow exception | ||
| // should not crash the runtime. | ||
| test( | ||
| "Response.json().body should not crash after catching stack overflow", | ||
| () => { | ||
| function F0() { | ||
| if (!new.target) { | ||
| throw "must be called with new"; | ||
| } | ||
| const v3 = this.constructor; | ||
| try { | ||
| new v3(); | ||
| } catch (e) {} | ||
| // This should not crash - it used to trigger an assertion failure | ||
| // due to a pending exception not being properly handled | ||
| Response.json().body; | ||
| } | ||
| // This should not crash | ||
| new F0(); | ||
| }, | ||
| { timeout: 60000 }, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regression test logic is good; drop the explicit timeout and consider naming
The test correctly reproduces the recursive stack overflow and verifies that Response.json().body no longer crashes simply by running the code path.
Two nits:
- Per test guidelines, avoid overriding timeouts; the test is synchronous and should not need
{ timeout: 60000 }. You can simplify to:
-test(
- "Response.json().body should not crash after catching stack overflow",
- () => {
+test("Response.json().body should not crash after catching stack overflow", () => {
// ...
- },
- { timeout: 60000 },
-);
+});- The file lives under
test/regression/issue/but the filename is descriptive rather than an issue-number pattern. If your regression suite typically uses numeric identifiers here, consider renaming to include the relevant issue ID for consistency (e.g. incorporating23921if that maps to a public issue).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { test } from "bun:test"; | |
| // Fixes: ENG-23921 | |
| // Accessing Response.json().body after catching a stack overflow exception | |
| // should not crash the runtime. | |
| test( | |
| "Response.json().body should not crash after catching stack overflow", | |
| () => { | |
| function F0() { | |
| if (!new.target) { | |
| throw "must be called with new"; | |
| } | |
| const v3 = this.constructor; | |
| try { | |
| new v3(); | |
| } catch (e) {} | |
| // This should not crash - it used to trigger an assertion failure | |
| // due to a pending exception not being properly handled | |
| Response.json().body; | |
| } | |
| // This should not crash | |
| new F0(); | |
| }, | |
| { timeout: 60000 }, | |
| ); | |
| import { test } from "bun:test"; | |
| // Fixes: ENG-23921 | |
| // Accessing Response.json().body after catching a stack overflow exception | |
| // should not crash the runtime. | |
| test("Response.json().body should not crash after catching stack overflow", () => { | |
| function F0() { | |
| if (!new.target) { | |
| throw "must be called with new"; | |
| } | |
| const v3 = this.constructor; | |
| try { | |
| new v3(); | |
| } catch (e) {} | |
| // This should not crash - it used to trigger an assertion failure | |
| // due to a pending exception not being properly handled | |
| Response.json().body; | |
| } | |
| // This should not crash | |
| new F0(); | |
| }); |
🤖 Prompt for AI Agents
In test/regression/issue/response-body-crash-after-stack-overflow.test.ts around
lines 1-25, remove the unnecessary explicit test timeout object ({ timeout:
60000 }) since the test is synchronous and doesn't need a custom timeout, and
optionally rename the file to follow the regression suite's numeric issue
pattern (e.g., include 23921) if your repo prefers issue-numbered filenames for
consistency; keep the test body otherwise unchanged.
Summary
Response.json().bodyafter catching a stack overflow exceptionDECLARE_THROW_SCOPEandRETURN_IF_EXCEPTIONtoReadableStream__emptyandReadableStream__usedfunctionsRoot Cause
When JavaScript code catches an exception with try/catch, the C++ VM still has the "exception pending" flag set. If a C++ function subsequently calls JavaScript code without explicitly checking/handling the exception state, JavaScriptCore's exception scope asserts: "Unexpected exception observed".
The
ReadableStream__emptyandReadableStream__usedfunctions were calling JavaScript functions viaJSC::callwithout proper throw scope handling.Test plan
test/regression/issue/response-body-crash-after-stack-overflow.test.tsbun bd test test/regression/issue/response-body-crash-after-stack-overflow.test.tsFixes: ENG-23921
🤖 Generated with Claude Code