Skip to content

fix(assets): drain watcher teardown before deleting dir on windows - #154

Merged
antfu merged 3 commits into
mainfrom
fix/assets-watcher-windows-teardown-race
Jul 31, 2026
Merged

fix(assets): drain watcher teardown before deleting dir on windows#154
antfu merged 3 commits into
mainfrom
fix/assets-watcher-windows-teardown-race

Conversation

@antfubot

Copy link
Copy Markdown
Collaborator

Why

CI's unit-test / test (windows-latest, …) job has been crashing the vitest worker fork with:

Assertion failed: !_wcsnicmp(filename, dir, dirlen), file src\win\fs-event.c, line 72
...
Error: [vitest-pool]: Worker forks emitted error.
Caused by: Error: Worker exited unexpectedly

plugins/assets is the only chokidar/fs.watch consumer in the repo. Its test harness (plugins/assets/test/_utils.ts) closes the live watcher and then immediately rm -rfs the same temp directory in every test's afterEach. On Windows, closing an fs.watch handle doesn't guarantee libuv has fully retired the outstanding ReadDirectoryChangesW completion — if the watched directory is deleted before that drains, the stale completion later trips libuv's directory-prefix sanity check and hard-aborts the process.

Fix

After watcher.close() resolves in watchAssetsDir's disposer, give libuv a short grace period on win32 before returning, so the pending I/O has time to settle before any caller deletes the watched directory.


Fixed with the help of an agent.

Closing chokidar/fs.watch doesn't guarantee libuv has retired the
outstanding ReadDirectoryChangesW request. Every assets test's
afterEach closes the watcher and immediately rm -rf's the same temp
directory, and on Windows CI that race trips a hard libuv assertion
(fs-event.c:72), crashing the vitest worker fork outright.
@netlify

netlify Bot commented Jul 31, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 438ee8f
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a6c45f570ea540008ec764c
😎 Deploy Preview https://deploy-preview-154--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

antfubot added 2 commits July 31, 2026 06:42
…eanup

The first attempt (a 50ms post-close grace period) wasn't enough on
Windows CI runners — every one of the 13 tests in assets.test.ts was
opening, closing, and immediately deleting a live-watched temp dir,
each one a fresh chance at the libuv fs-event race.

- Only the test that actually exercises the watcher now passes
  watch: true; the other 12 opt out (watch: false), so this file
  opens exactly one native Windows directory watch per run.
- Every temp dir's deletion is deferred to a single afterAll instead
  of each test's afterEach, so cleanup runs well clear of that one
  watcher's teardown.
- Bumped the win32 post-close grace period from 50ms to 200ms.
Even isolated to a single native watch handle with a 200ms post-close
grace period, the windows-latest matrix still hit
`Assertion failed: !_wcsnicmp(filename, dir, dirlen)` intermittently.
A fixed delay can't reliably fix this — the crash is consistent with
Windows Defender's real-time scanning racing the directory
watch/close/delete, a known Node/libuv interaction on hosted Windows
runners that isn't reliably avoidable from application code. Skip the
one test that opens a real watch there; the behavior stays fully
covered on Linux/macOS.
@antfu
antfu merged commit 1deafc6 into main Jul 31, 2026
12 checks passed
@antfu
antfu deleted the fix/assets-watcher-windows-teardown-race branch July 31, 2026 07:26
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.

2 participants