inspector: handle BigInt/Symbol in returnByValue instead of asserting - #36841
inspector: handle BigInt/Symbol in returnByValue instead of asserting#36841robobun wants to merge 4 commits into
Conversation
Runtime.evaluate (and callFunctionOn / evaluateOnCallFrame) with returnByValue:true on a result that contains a BigInt or Symbol reached ASSERT_NOT_REACHED in Inspector::jsToInspectorValue, aborting an assertions build of the debuggee. Release builds fell through to nullptr and reported the unrelated 'Object has too long reference chain' error. The fix is in oven-sh/WebKit#384: jsToInspectorValue now returns nullptr explicitly for BigInt/Symbol (they have no JSON representation), and the error surfaced to the client is 'Object couldn't be returned by value' (matching V8's inspector). Bump WEBKIT_VERSION to pick that up and add a --inspect regression test for [1n], {a:1n}, Symbol(), {b:Symbol()}.
|
Status: oven-sh/WebKit#384 CI is green across all 38 lanes and the Against the original repro on the assertions-enabled (was Fail-before is intact ( |
|
Updated 2:06 PM PT - Aug 3rd, 2026
✅ @robobun, your commit 34087f992d72dfeedc646b9955a015c1fcfc0174 passed in 🧪 To try this PR locally: bunx bun-pr 36841That installs a local version of the PR into your bun-36841 --bun |
|
Warning Review limit reached
Next review available in: 5 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThe PR updates the default WebKit preview release tag and adds inspector regression tests for ChangesWebKit preview update
Inspector evaluation regressions
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/build/deps/webkit.ts`:
- Line 6: Update WEBKIT_VERSION to a published immutable WebKit revision that
exists on the remote, replacing the unavailable
autobuild-preview-pr-384-0cd81acb preview tag. Use the WebKit webkitVersion or
prebuilt.identity value as the revision source, not a separate dependency commit
field.
In `@test/cli/inspect/inspect.test.ts`:
- Around line 423-430: Update the WebSocket waits around the connection and
reply promises to settle on every terminal event: reject both phases on close
and error, catch JSON.parse failures and reject the reply promise, and remove
all attached listeners after resolve or reject. Preserve successful open and
message resolution while ensuring no promise remains pending.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9b9dc113-4169-4058-9dc0-0d5972574e52
📒 Files selected for processing (2)
scripts/build/deps/webkit.tstest/cli/inspect/inspect.test.ts
There was a problem hiding this comment.
Test changes look good after the follow-ups — the hoisted spawnInspectee() now kills the child on the discovery-failure path and both WebSocket waits reject on close/error, so my earlier inline notes are resolved. Not approving because the substantive fix is a WebKit dependency bump (oven-sh/WebKit#384) that a human should sign off on, and WEBKIT_VERSION is still on the autobuild-preview-pr-384-* tag pending that PR's merge.
What was reviewed:
spawnInspectee()hoist: verified the two existing http-metadata callers still assignmetadataInspecteebefore any assertion soafterEachcleanup is intact.- New returnByValue tests: exact-message assertion on the V8 wording, debuggee-liveness check via
exitCode/signalCode, and the bare-1ncontrol case guarding against over-broad rejection. - Confirmed
{once: true}on the open-phasecloselistener means a later post-reply close cannot spuriously reject an already-settled promise.
Extended reasoning...
Overview
This PR carries a fix that lives in oven-sh/WebKit#384 (adding a BigInt/Symbol arm to Inspector::jsToInspectorValue and rewording the fallthrough error). On the Bun side it does two things: bumps WEBKIT_VERSION in scripts/build/deps/webkit.ts to a preview build of that WebKit change, and adds a regression describe in test/cli/inspect/inspect.test.ts covering [1n], {a:1n}, Symbol(), {b:Symbol()}, plus a bare-1n control. Follow-up commits hoisted the pre-existing spawnInspectee() helper to file scope (reused by the http-metadata describe and the new describe), added child.kill() on the URL-discovery failure path, and wired every terminal WebSocket event to reject the awaited promises.
Security risks
None introduced by the test file. The WebKit bump changes vendored JS-engine code; the specific patch (returning nullptr for BigInt/Symbol in the inspector's JSON serializer and changing an error string) is narrow, but any WebKit version change is engine-level and I cannot review the upstream diff from here.
Level of scrutiny
High, because of the vendored-dependency bump. REVIEW.md flags "Dependencies & vendoring" as a situational area needing its own checklist, and the JS engine is the most load-bearing dependency in the tree. The Bun-side test changes on their own would be low-scrutiny — they follow existing patterns in the same file, are hermetic (spawn a local inspectee on 127.0.0.1:0, no network), and assert exact error shape rather than substring matches.
Other factors
WEBKIT_VERSIONis currentlyautobuild-preview-pr-384-0cd81acb, which the PR body and author explicitly say must be swapped for the merged main sha before this lands. Approving now would greenlight a preview pin.- My two prior inline comments (third copy of the spawn/discover block; cleanup-ordering regression from the hoist) were both addressed in ca97e16 and 34087f9 respectively; I re-read the resulting code and both fixes look correct.
- The
describe("websocket", ...)block still has its own inline copy of the discovery loop — the author left it because it parameterises--inspect=...per test case, which is a reasonable scope boundary for this PR. - No bugs were reported by the bug-hunting pass on the current head.
What does this PR do?
Runtime.evaluate/Runtime.callFunctionOn/Debugger.evaluateOnCallFramewithreturnByValue: trueon a result that holds a BigInt or Symbol reachedASSERT_NOT_REACHEDinInspector::jsToInspectorValue(InjectedScriptBase.cpp:96), aborting an assertions build of the debuggee. Release builds fell through tonullptrand the caller reported the unrelated "Object has too long reference chain (must not be longer than 1000)" error.Repro
Before (assertions build):
debuggee exits SIGABRT.
Before (release):
{"error":{"code":-32000,"message":"Object has too long reference chain (must not be longer than 1000)"}}, debuggee alive.Also reproduces with
({a:1n}),Symbol("s"),({b:Symbol()}), and overDebugger.evaluateOnCallFramewhile paused. A bare1nis fine becauseInjectedScriptSource.jsnever stores it onRemoteObject.value.Cause
jsToInspectorValuehas arms for null/undefined, boolean, number, string, and object, thenASSERT_NOT_REACHED(). BigInt and Symbol (introduced after this code was written) fall through. WhenreturnByValueis set,InjectedScriptSource.jsstores the raw value onRemoteObject.valueand the C++ side recurses into it.Fix
The fix is in oven-sh/WebKit#384:
isBigInt() || isSymbol()arm returningnullptr(unserializable), avoiding the assert.node -e '...'returns the same for[1n]) and accurate for both the depth-limit and unserializable-primitive cases.This PR bumps
WEBKIT_VERSIONto the preview build of that change and adds a--inspectregression test covering[1n],{a:1n},Symbol(),{b:Symbol()}, plus the already-working bare1n.Verification
After: all 5 pass; the debuggee stays alive on an assertions build.
Note:
WEBKIT_VERSIONcurrently points at theautobuild-preview-pr-384-*tag and will be switched to the merged oven-sh/WebKit main sha before this PR merges.