Skip to content

repl: pass objectGroup to Runtime.awaitPromise to prevent GC collection#64764

Open
DivyanshuX9 wants to merge 1 commit into
nodejs:mainfrom
DivyanshuX9:fix/repl-inspector-promise-collected
Open

repl: pass objectGroup to Runtime.awaitPromise to prevent GC collection#64764
DivyanshuX9 wants to merge 1 commit into
nodejs:mainfrom
DivyanshuX9:fix/repl-inspector-promise-collected

Conversation

@DivyanshuX9

@DivyanshuX9 DivyanshuX9 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #64762.

When ReplInspectorChannel.evaluate() evaluates an expression that returns a promise, it issues two inspector commands in sequence:

  • Runtime.evaluate
  • Runtime.awaitPromise

Runtime.evaluate already passes objectGroup, placing the remote promise object into the REPL's named object group. However, Runtime.awaitPromise does not pass objectGroup.

Under GC pressure, the remote promise object can be collected before Runtime.awaitPromise completes, causing the inspector to return:

Inspector error -32000: Promise was collected

Instead of reporting the user's original exception, the REPL surfaces ERR_INSPECTOR_COMMAND.

Change

Pass objectGroup to Runtime.awaitPromise so the remote promise object remains retained for the duration of the await.

return this.postInterruptible('Runtime.awaitPromise', {
  __proto__: null,
  promiseObjectId: response.result.objectId,
  returnByValue: params.returnByValue,
  generatePreview: params.generatePreview,
+ objectGroup: this.objectGroup,
}, breakOnSigint);

Why

The Inspector protocol allows Runtime.awaitPromise to receive an objectGroup. Passing the same object group used during Runtime.evaluate keeps the remote promise object alive until the await operation completes, preventing it from being collected while the inspector request is in progress.

Testing

The existing test, test/parallel/test-repl-pretty-stack-custom-writer.mjs, already exercises this code path. This change makes that test reliable under GC pressure, so no additional test is required.

Related

Copilot AI review requested due to automatic review settings July 26, 2026 16:46
@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. repl Issues and PRs related to the REPL subsystem. labels Jul 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a GC-related race in the inspector-backed REPL evaluator when awaiting promise results. It ensures the remote Promise handle created by Runtime.evaluate remains retained until Runtime.awaitPromise completes, preventing Inspector error -32000: Promise was collected from surfacing as ERR_INSPECTOR_COMMAND.

Changes:

  • Pass objectGroup: this.objectGroup to Runtime.awaitPromise in ReplInspectorChannel.evaluate().
  • Update the surrounding comment to document the GC-retention rationale for the two-step inspector flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

When the inspector-backed REPL evaluates a promise-returning
expression, Runtime.evaluate stores the remote promise object in an
objectGroup.

Runtime.awaitPromise did not pass objectGroup. Under GC pressure,
the remote promise object could be collected before the await
completed, causing the inspector to report:

  -32000: Promise was collected

This surfaced in the REPL as ERR_INSPECTOR_COMMAND instead of the
user's original exception.

Pass objectGroup to Runtime.awaitPromise so the promise remains
retained until the await completes.

Fixes: nodejs#64762
Signed-off-by: Divyanshu Sharma <divyanshu88999@gmail.com>
@DivyanshuX9
DivyanshuX9 force-pushed the fix/repl-inspector-promise-collected branch from c51f3cd to a16deb3 Compare July 26, 2026 16:57
// Pass objectGroup so the promise remote object stays retained for the
// duration of the await and cannot be collected by a GC cycle between
// the two inspector calls.
return this.postInterruptible('Runtime.awaitPromise', {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@avivkeller avivkeller left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect. See https://chromium-review.googlesource.com/c/v8/v8/+/8123081 for a proper fix for this issue.

@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.15%. Comparing base (4a5eb1c) to head (a16deb3).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #64764   +/-   ##
=======================================
  Coverage   90.15%   90.15%           
=======================================
  Files         744      744           
  Lines      242517   242520    +3     
  Branches    45688    45682    -6     
=======================================
+ Hits       218642   218649    +7     
- Misses      15358    15367    +9     
+ Partials     8517     8504   -13     
Files with missing lines Coverage Δ
lib/internal/repl/inspector.js 90.90% <100.00%> (+0.10%) ⬆️

... and 31 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. repl Issues and PRs related to the REPL subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

repl: Runtime.awaitPromise races with GC when objectGroup is not passed Body

5 participants