You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
repl: Runtime.awaitPromise races with GC when objectGroup is not passed Body #64762
How often does it reproduce? Is there a required condition?
Not reliably reproducible on normal builds.
Consistently observed on the shared-libraries CI configuration, where GC pressure is higher.
The failure requires a GC cycle to occur between Runtime.evaluate and Runtime.awaitPromise.
What is the expected behavior? Why is that the expected behavior?
The REPL should report the user's actual exception.
Expected output:
Uncaught Error: foo[a]
The remote promise object should remain available until Runtime.awaitPromise completes.
What do you see instead?
Instead of the user's exception, the inspector reports:
Uncaught Error [ERR_INSPECTOR_COMMAND]:
Inspector error -32000: Promise was collected
This causes test/parallel/test-repl-pretty-stack-custom-writer.mjs to fail.
Additional information
Runtime.awaitPromise accepts an optional objectGroup parameter.
Passing the same object group used by Runtime.evaluate prevents the remote promise object from being collected while the await operation is in progress.
Under GC pressure (observed on the shared-libraries CI configuration), a collection cycle can occur between these two inspector calls. If the remote promise object is collected before Runtime.awaitPromise completes, the inspector returns:
Inspector error -32000: Promise was collected
Instead of reporting the user's original exception, the REPL surfaces:
Error [ERR_INSPECTOR_COMMAND]: Inspector error -32000: Promise was collected
This causes test/parallel/test-repl-pretty-stack-custom-writer.mjs to fail.
Failing assertion
Expected:
Uncaught Error: foo[a]
Actual:
Uncaught Error [ERR_INSPECTOR_COMMAND]: Inspector error -32000: Promise was collected
Root cause
Runtime.awaitPromise accepts an optional objectGroup parameter.
The promise object is initially associated with the REPL's object group by Runtime.evaluate, but Runtime.awaitPromise does not explicitly pass that group. Under GC pressure, the remote promise object can be collected before the await operation completes, causing the inspector command to fail.
Proposed fix
Pass objectGroup to Runtime.awaitPromise:
diff --git a/lib/internal/repl/inspector.js b/lib/internal/repl/inspector.js@@ -180,9 +180,11 @@ class ReplInspectorChannel {
- // Hold the promise open until it resolves or rejects,- // so we can return the final value.+ // Hold the promise open until it resolves or rejects.+ // Pass objectGroup so the remote promise object remains retained for the+ // duration of the await operation.
return this.postInterruptible('Runtime.awaitPromise', {
__proto__: null,
promiseObjectId: response.result.objectId,
returnByValue: params.returnByValue,
generatePreview: params.generatePreview,
+ objectGroup: this.objectGroup,
}, breakOnSigint);
Passing the existing object group keeps the remote promise object alive until the await operation completes and prevents the race.
Affected file
lib/internal/repl/inspector.js
This code was introduced by #64034 and is not yet present on main.
The fix can be applied directly to that PR or submitted as a follow-up after it merges.
Updating the test to accept ERR_INSPECTOR_COMMAND would mask the underlying issue instead of fixing it.
The issue is reproducible on the shared-libraries CI configuration but is difficult to reproduce consistently on standard builds because it depends on GC timing.
i was not sure about upstreamV8 much since i got this issue in my pr #63651 , so i tried to dig why am i facing the failure, So i have a small fix for that so i just raised the issue
Thanks for the pointer. I wasn't aware of the upstream V8 issue.
My understanding was that passing objectGroup to Runtime.awaitPromise keeps the remote promise retained for the duration of the await and avoids the failure on the Node.js side.
Do you think this workaround is still worth taking in Node, or should we rely entirely on the upstream V8 fix?
I had assumed objectGroup was supported by Runtime.awaitPromise, but i think you're right that it isn't part of the protocol. I'll take another look at the V8 change you linked and understand how ProtocolPromiseHandler::setWeak() is involved before pursuing this further.
Activity
DivyanshuX9 commentedon Jul 26, 2026
What happened
The inspector-backed REPL introduced in #64034 evaluates promise-returning expressions using two sequential inspector commands:
Runtime.evaluate(returns a remote promiseobjectId)Runtime.awaitPromise(waits for the promise to settle)Runtime.evaluatepassesobjectGroup: this.objectGroup, placing the remote promise object into the REPL's named object group:However,
Runtime.awaitPromisedoes not passobjectGroup:Under GC pressure (observed on the shared-libraries CI configuration), a collection cycle can occur between these two inspector calls. If the remote promise object is collected before
Runtime.awaitPromisecompletes, the inspector returns:Instead of reporting the user's original exception, the REPL surfaces:
This causes
test/parallel/test-repl-pretty-stack-custom-writer.mjsto fail.Failing assertion
Expected:
Actual:
Root cause
Runtime.awaitPromiseaccepts an optionalobjectGroupparameter.The promise object is initially associated with the REPL's object group by
Runtime.evaluate, butRuntime.awaitPromisedoes not explicitly pass that group. Under GC pressure, the remote promise object can be collected before the await operation completes, causing the inspector command to fail.Proposed fix
Pass
objectGrouptoRuntime.awaitPromise:Passing the existing object group keeps the remote promise object alive until the await operation completes and prevents the race.
Affected file
lib/internal/repl/inspector.jsThis code was introduced by #64034 and is not yet present on
main.Additional notes
repl: use inspector over vm).ERR_INSPECTOR_COMMANDwould mask the underlying issue instead of fixing it.Archkon commentedon Jul 26, 2026
DivyanshuX9 commentedon Jul 26, 2026
i was not sure about upstreamV8 much since i got this issue in my pr #63651 , so i tried to dig why am i facing the failure, So i have a small fix for that so i just raised the issue
repl: pass objectGroup to Runtime.awaitPromise
Archkon commentedon Jul 26, 2026
DivyanshuX9 commentedon Jul 26, 2026
Thanks for the pointer. I wasn't aware of the upstream V8 issue.
My understanding was that passing objectGroup to Runtime.awaitPromise keeps the remote promise retained for the duration of the await and avoids the failure on the Node.js side.
Do you think this workaround is still worth taking in Node, or should we rely entirely on the upstream V8 fix?
Archkon commentedon Jul 26, 2026
DivyanshuX9 commentedon Jul 26, 2026
I had assumed objectGroup was supported by Runtime.awaitPromise, but i think you're right that it isn't part of the protocol. I'll take another look at the V8 change you linked and understand how ProtocolPromiseHandler::setWeak() is involved before pursuing this further.
avivkeller commentedon Jul 26, 2026
@DivyanshuX9 @Archkon The proposed fix will not work. I'm already coordinating with V8 to fix this. See https://chromium-review.googlesource.com/c/v8/v8/+/8123081