Skip to content

Fix disposable leak warning from in-process node.js file watcher#320246

Merged
roblourens merged 2 commits into
mainfrom
roblou/fix-nodejs-watcher-dispose-race
Jun 6, 2026
Merged

Fix disposable leak warning from in-process node.js file watcher#320246
roblourens merged 2 commits into
mainfrom
roblou/fix-nodejs-watcher-dispose-race

Conversation

@roblourens
Copy link
Copy Markdown
Member

Fixes #320245

NodeJSFileWatcherLibrary.watch() awaited doWatch() and then called this._register() on the result. If the watcher instance was disposed while that promise was in flight, _store was already disposed by the time _register ran, producing:

Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!

and leaking the underlying fs.watch handle.

This surfaces frequently in the agent host because non-recursive file watching runs in-process there, and SessionCustomizationDiscovery tears down and recreates watchers on the same paths whenever workspace files change.

The fix uses the existing thenRegisterOrDispose helper (already used elsewhere in the same file) so the resolved handle is disposed instead of registered + leaked when the watcher is torn down mid-flight.

Type-check (compile-check-ts-native) passes.

(Written by Copilot)

NodeJSFileWatcherLibrary.watch() awaited doWatch() and then called
this._register() on the result. If the watcher was disposed during that
async window, _store was already disposed, producing a "disposable added
to a disposed store" warning and leaking the fs.watch handle.

Use thenRegisterOrDispose so the resolved handle is disposed instead of
registered when the watcher is torn down mid-flight. This is common in
the agent host where non-recursive watching runs in-process and
SessionCustomizationDiscovery churns watchers on file changes.

Fixes #320245

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 6, 2026 17:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 disposable-registration race in the in-process Node.js file watcher implementation that could emit “Trying to add a disposable to a DisposableStore that has already been disposed of…” and leak the underlying fs.watch handle when the watcher is disposed while doWatch() is still resolving (notably common in the agent host due to frequent watcher churn).

Changes:

  • Replaces this._register(await this.doWatch(...)) with thenRegisterOrDispose(this.doWatch(...), this._store) to ensure the resolved watch handle is disposed (not registered) if the watcher’s store was already disposed mid-flight.
  • Adds an explanatory comment documenting the async disposal race and the intent of the fix.
Show a summary per file
File Description
src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts Uses thenRegisterOrDispose to avoid registering into a disposed store and to dispose resolved watcher handles instead of leaking them.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@roblourens roblourens marked this pull request as ready for review June 6, 2026 17:21
@roblourens roblourens enabled auto-merge (squash) June 6, 2026 17:21
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@roblourens roblourens merged commit acc17e1 into main Jun 6, 2026
25 checks passed
@roblourens roblourens deleted the roblou/fix-nodejs-watcher-dispose-race branch June 6, 2026 17:59
@vs-code-engineering vs-code-engineering Bot added this to the 1.124.0 milestone Jun 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent host: "Trying to add a disposable to a DisposableStore that has already been disposed of" from in-process node.js file watcher

3 participants