Skip to content

fs.watch: endless file events reported #61398

Open

Description

@bpasero

Version

v22.21.1

Platform

Microsoft Windows NT 10.0.26200.0 x64

Subsystem

No response

What steps will reproduce the bug?

  • create a folder vscode
  • run this command in that folder mkdir .vscode && echo {"editor.fontSize": 33}>.vscode\settings.json
  • run the following node.js script in a terminal pointing to the folder vscode/.vscode
  • run this command in that folder rmdir /s /q .vscode\ && mkdir .vscode && echo {"editor.fontSize": 33}>.vscode\settings.json
const fs = require("fs");

fs.watch("<path to a folder>/.vscode", (eventType, filename) => {
    if (filename) {
        console.log(`Event Type: ${eventType}`);
        console.log(`Filename: ${filename}`);
    } else {
        console.log("Filename not provided");
    }
});

How often does it reproduce? Is there a required condition?

Always.

What is the expected behavior? Why is that the expected behavior?

After running the last command there should be change events reported in an endless fashion.

What do you see instead?

Endless reports of:

Filename: \\?\C:\Users\bpasero\Desktop\testing-watcher\.vscode
Event Type: rename
Filename: \\?\C:\Users\bpasero\Desktop\testing-watcher\.vscode
Event Type: rename
Filename: \\?\C:\Users\bpasero\Desktop\testing-watcher\.vscode
Event Type: rename
Filename: \\?\C:\Users\bpasero\Desktop\testing-watcher\.vscode
Event Type: rename

Additional information

Originally reported in VS Code repo as microsoft/vscode#287800

Activity

  1. justanotheranonymoususer commented on Jan 16, 2026

    @justanotheranonymoususer

    I also wrote some observations here: microsoft/vscode#263718 (comment)
    Actual ReadDirectoryChangesW call is in libuv, so might also be a libuv bug.

  2. StefanStojanovic commented on Jan 29, 2026

    @StefanStojanovic
    Contributor

    I've investigated this issue a bit. The root cause is not deleting and recreating the folder, but deleting it permanently (similar to Shift+Delete). When I tested deleting regularly (Delete from the File Explorer), I see this:

    Event Type: change
    Filename: settings.json
    

    However, if I empty the recycle bin (permanent deletion), the same behavior is reached.

    Regular deletion to the Recycle Bin is actually a move operation, which makes the original path invalid, thus the next ReadDirectoryChangesW call fails, and the watcher stops cleanly. Permanent deletion marks the directory for deletion, but since libuv holds an open handle, NTFS can't fully delete it yet. Instead, it moves the directory to $Extend$Deleted (a special NTFS holding area), and the handle remains valid, continuing to report events on this "zombie" path. This causes the infinite loop because ReadDirectoryChangesW keeps succeeding without errors.

    I've tried a fix locally, and it worked, but I'll have to open a PR in libuv as that's where the root cause lies.

  3. added a commit that references this issue on Jan 29, 2026
  4. added a commit that references this issue on Mar 17, 2026
  5. added a commit that references this issue on Mar 31, 2026
  6. StefanStojanovic commented on Mar 31, 2026

    @StefanStojanovic
    Contributor

    The fix for this has landed in the libuv project. The next time libuv is released and pulled into Node.js, this issue will be resolved.

  7. added a commit that references this issue on Jun 9, 2026
  8. github-actions commented on Jul 20, 2026

    @github-actions
    Contributor

    This issue has been marked as stale due to 90 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  9. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Jul 20, 2026
  10. relmer commented on Jul 29, 2026

    @relmer

    Still relevant — reproduced in the wild today (2026-07-29) on VS Code 1.130.0, Windows 11 10.0.26200, NTFS, no unusual filesystem drivers.

    Two watcher utility processes (Code.exe --utility-sub-type=node.mojom.NodeService) were pegged at ~100% of a core each for 14 hours (~24% of an 8-core machine), having burned 13.9 CPU-hours apiece. Both held open handles under C:\$Extend\$Deleted\; the six idle sibling utility processes held zero — matching the signature described in microsoft/vscode#287800.

    Native stack of the spinning thread confirms the loop is in libuv's fs-event path:

    ntdll!NtQueryInformationFile
    KERNELBASE!GetFileInformationByHandleEx
    Code!uv_fs_event_stop+0x194      <- nearest exported symbol, not necessarily the actual frame
    Code!uv_run
    

    Time split on that thread was ~75% kernel / 25% user, consistent with a syscall retry loop rather than a JS-side spin. No memory or handle growth over the 14 hours — pure spin, and no file in either watched tree had changed for hours.

    This also lines up with @StefanStojanovic's analysis above: both affected workspaces had a watched directory permanently deleted (not sent to the Recycle Bin), leaving the zombie handle behind.

    Noting for the stale bot: the fix is reported above as landed in libuv on 2026-03-31, but libuv's latest release (v1.52.1) is dated 2026-03-06 — it predates the fix, so it hasn't been able to flow into Node/Electron/VS Code yet. Still reproducing on current VS Code as of today.

  11. removed
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions