Turbopack: `watchOptions.pollIntervalMs` permanently drops file edits on Windows
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.4k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/DenisCDev/turbopack-polling-drop
To Reproduce
npm install
# polling watcher
POLL_MS=1000 SESSIONS=5 EDITS=5 npm run probe
# same edit pattern, native watcher, as a control
POLL_MS=0 SESSIONS=5 EDITS=5 npm run probe
Each session removes .next, boots a fresh next dev, rewrites lib/mod.ts five times in a row, and records how long until the served page reflects each new value — or X if it never did within WINDOW_MS (default 8000 ms, eight full poll intervals).
Current vs. Expected behavior
Current. With watchOptions.pollIntervalMs set, edits are lost silently and permanently. The native watcher, running the identical pattern on the same machine, loses none.
watcher=polling 1000ms | 5 sessions x 5 edits | window 8000ms
session 1: 889 763 1028 1044 1053
session 2: 801 X 287 1052 1075
session 3: 691 1021 1037 1029 1060
session 4: 665 X 264 1021 1036
session 5: 739 X 218 1046 1037
detected: 22/25
file mtime advanced on 25/25 writes
watcher=native | 5 sessions x 5 edits | window 8000ms
session 1: 374 95 75 90 67
session 2: 97 82 74 90 72
session 3: 97 90 397 89 419
session 4: 96 87 78 97 94
session 5: 95 171 75 89 83
detected: 25/25
Repeated runs of the polling arm gave 15/25, 20/25 and 22/25. The native arm has not lost an edit in any run I have done.
Two objections answered in the output itself:
- The write reaches disk. The probe stats the file around every write; mtime advanced on 25/25, including every lost edit.
- The loss is permanent, not slow. With
WINDOW_MS=90000— ninety poll intervals — a lost edit still never arrives (8/9 detected in that run). Only writing the file again brings the route back.
Expected. An edit that is on disk is eventually reflected, however soon it followed the previous one.
One correlation, offered as an observation. Losses track the latency of the preceding edit. While edits are reflected in ~200–800 ms, faster than the configured 1000 ms interval, the next one tends to be lost; once latency settles at ~1000 ms, losses stop for the rest of the session. I have not identified what detects a change in 200 ms while polling is enabled.
I want to be clear about the limit of this measurement: the probe only observes that the dev server never serves the new value. It cannot tell an event that was never emitted from one that was emitted and not acted on. There is no instrumentation inside Turbopack here.
Provide environment information
Operating System:
Platform: win32
Arch: x64
Version: Windows 11 Home
Available memory (MB): 16290
Available CPU cores: 12
Binaries:
Node: 22.22.0
npm: 10.9.4
Yarn: 1.22.22
pnpm: 10.29.3
Relevant Packages:
next: 16.3.1-canary.8 // Latest available version is detected (16.3.1-canary.8).
eslint-config-next: N/A
react: 19.2.0
react-dom: 19.2.0
typescript: 7.0.2
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Turbopack
Which stage(s) are affected? (Select all that apply)
next dev (local)
Additional context
This is not an old, unfixed bug. #96440 landed 2026-08-07 22:40 UTC, 44 minutes before v16.3.1-canary.8 was tagged, so the build measured above already contains it. The polling watcher still drops edits on native Windows with that fix in place.
watchOptions.pollIntervalMs is the fallback for environments where native watching does not work — Docker, WSL2, network drives, VMs — which is exactly where users have no alternative. The option is also undocumented today: no JSDoc in config-shared, nothing in next/dist/docs/, and the docs PR (#80687) has been open since 2025-06-19.
One asymmetry visible from outside Turbopack, which may or may not be related: the dev server logs seven watch error (...): Io(Os { ..., kind: NotFound }) lines per session in the polling arm and zero in the native arm. None of them is the edited file, which exists and is watched. The probe keeps each session's server output under probe-logs/.
Why closely spaced writes are not a synthetic case: they are the normal output of format-on-save, git checkout and merge, codemods, and CLI coding agents that write several files in a burst before requesting the page.
Two caveats. It is intermittent — whether a given session loses anything varies, and short runs can come back clean; every run of 25 observations I attempted reproduced losses. And I have only tested native Windows; I have no macOS or Linux machine to compare against, so I cannot say whether this is Windows-specific.
Happy to run candidate patches or extra instrumentation here — each arm of the repro takes about two minutes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Run the polling and native watcher commands from the linked reproduction, using the stated Windows environment, then compare which edits to lib/mod.ts are served. Review the probe output and probe-logs/ for the polling arm, especially the watch error lines, and trace the next dev path handling watchOptions.pollIntervalMs. Done means every on-disk edit is eventually reflected, including closely spaced writes, without regressing native watching.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nextjs, node.js, typescript
- Domain
- build-system, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100