Skip to content

Conversation

@bgw
Copy link
Member

@bgw bgw commented Jan 16, 2026

In an attempt to reproduce #88382, this tries creating and updating a bunch of symlinks/junction points in a tight loop with some parallelism. However, I've been unable to reproduce the error reported in that discussion.

I don't care about the code quality here, so this was LLM-generated with very lightweight review.

A simplified version of the fuzzer is also included as a unit test in turbo-tasks-fs. This version only does a few iterations and runs very quickly.

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 16, 2026

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing bgw/symlink-stress (b84ae7d) with canary (ddd02ab)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@bgw bgw requested a review from a team January 16, 2026 22:22
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Jan 16, 2026

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 456ms 455ms ▁▁▁▁▁
Cold (Ready in log) 440ms 439ms ▆▁▇▇▁
Cold (First Request) 1.192s 1.177s █▂▇█▁
Warm (Listen) 457ms 456ms ▁▁▁▁█
Warm (Ready in log) 443ms 443ms ▁▂▁▂▇
Warm (First Request) 341ms 342ms ▁▃▁██
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 455ms ████▁
Cold (Ready in log) 438ms 438ms █▆▇▁▅
Cold (First Request) 1.760s 1.775s ▄▂▅▂▃
Warm (Listen) 456ms 456ms ▅▅▅█▅
Warm (Ready in log) 437ms 438ms ▆▃▆▁█
Warm (First Request) 1.768s 1.781s ▃▁▄▃▃

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 4.294s 4.246s ▂█▂▃▆
Cached Build 4.315s 4.353s ▂█▁▃▄
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.145s 14.114s ▄▁▄█▄
Cached Build 14.229s 14.214s ▄▂▃█▄
node_modules Size 460 MB 460 MB █████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles: **432 kB** → **432 kB** ✅ -45 B

82 files with content-based hashes (individual files not comparable between builds)

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 760 B 765 B
Total 760 B 765 B ⚠️ +5 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 451 B 449 B
Total 451 B 449 B ✅ -2 B

📦 Webpack

Client

Main Bundles
Canary PR Change
2086.HASH.js gzip 169 B N/A -
2161-HASH.js gzip 5.41 kB N/A -
2747-HASH.js gzip 4.48 kB N/A -
4322-HASH.js gzip 52.7 kB N/A -
ec793fe8-HASH.js gzip 62.3 kB N/A -
framework-HASH.js gzip 59.8 kB 59.8 kB
main-app-HASH.js gzip 251 B 254 B 🔴 +3 B (+1%)
main-HASH.js gzip 38.7 kB 39.1 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
1596.HASH.js gzip N/A 169 B -
2658-HASH.js gzip N/A 52.4 kB -
6349-HASH.js gzip N/A 4.46 kB -
7019-HASH.js gzip N/A 5.43 kB -
b17a3386-HASH.js gzip N/A 62.3 kB -
Total 226 kB 226 kB ⚠️ +55 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 193 B
_error-HASH.js gzip 182 B 182 B
css-HASH.js gzip 336 B 335 B
dynamic-HASH.js gzip 1.8 kB 1.8 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 352 B 349 B
hooks-HASH.js gzip 385 B 384 B
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 259 B 258 B
link-HASH.js gzip 2.5 kB 2.51 kB
routerDirect..HASH.js gzip 319 B 317 B
script-HASH.js gzip 385 B 387 B
withRouter-HASH.js gzip 316 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.97 kB 7.96 kB ✅ -8 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 125 kB 125 kB
page.js gzip 243 kB 239 kB 🟢 4.84 kB (-2%)
Total 368 kB 363 kB ✅ -4.83 kB
Middleware
Canary PR Change
middleware-b..fest.js gzip 616 B 619 B
middleware-r..fest.js gzip 155 B 156 B
middleware.js gzip 33 kB 33.3 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 34.7 kB 34.9 kB ⚠️ +205 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 738 B 738 B
Total 738 B 738 B
Build Cache
Canary PR Change
0.pack gzip 3.68 MB 3.69 MB 🔴 +7.73 kB (+0%)
index.pack gzip 102 kB 100 kB 🟢 1.14 kB (-1%)
index.pack.old gzip 102 kB 101 kB
Total 3.89 MB 3.89 MB ⚠️ +5.91 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 305 kB 305 kB
app-page-exp..prod.js gzip 162 kB 162 kB
app-page-tur...dev.js gzip 305 kB 305 kB
app-page-tur..prod.js gzip 162 kB 162 kB
app-page-tur...dev.js gzip 302 kB 302 kB
app-page-tur..prod.js gzip 160 kB 160 kB
app-page.run...dev.js gzip 302 kB 302 kB
app-page.run..prod.js gzip 160 kB 160 kB
app-route-ex...dev.js gzip 68.8 kB 68.8 kB
app-route-ex..prod.js gzip 47.6 kB 47.6 kB
app-route-tu...dev.js gzip 68.8 kB 68.8 kB
app-route-tu..prod.js gzip 47.6 kB 47.6 kB
app-route-tu...dev.js gzip 68.4 kB 68.4 kB
app-route-tu..prod.js gzip 47.4 kB 47.4 kB
app-route.ru...dev.js gzip 68.4 kB 68.4 kB
app-route.ru..prod.js gzip 47.4 kB 47.4 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 41.2 kB 41.2 kB
pages-api-tu..prod.js gzip 31.3 kB 31.3 kB
pages-api.ru...dev.js gzip 41.1 kB 41.1 kB
pages-api.ru..prod.js gzip 31.2 kB 31.2 kB
pages-turbo....dev.js gzip 50.8 kB 50.8 kB
pages-turbo...prod.js gzip 38.2 kB 38.2 kB
pages.runtim...dev.js gzip 50.8 kB 50.8 kB
pages.runtim..prod.js gzip 38.2 kB 38.2 kB
server.runti..prod.js gzip 62.2 kB 62.2 kB
Total 2.71 MB 2.71 MB ✅ -1 B

@bgw bgw marked this pull request as ready for review January 16, 2026 22:41
Copy link
Member Author

bgw commented Jan 20, 2026

Merge activity

@bgw bgw force-pushed the bgw/move-fs-watcher branch 2 times, most recently from fffca45 to b17a020 Compare January 21, 2026 18:10
@bgw bgw force-pushed the bgw/symlink-stress branch from e02a9ba to ee8dc1e Compare January 21, 2026 18:10
@bgw bgw changed the base branch from bgw/move-fs-watcher to graphite-base/88667 January 21, 2026 18:41
bgw added a commit that referenced this pull request Jan 21, 2026
…8666)

This PR just moves things around for #88667.

I don't care about the code quality here, so this was LLM-generated with very lightweight review.
@bgw bgw force-pushed the graphite-base/88667 branch from b17a020 to ddd02ab Compare January 21, 2026 18:42
@bgw bgw force-pushed the bgw/symlink-stress branch from ee8dc1e to d71635f Compare January 21, 2026 18:42
@graphite-app graphite-app bot changed the base branch from graphite-base/88667 to canary January 21, 2026 18:42
@bgw bgw force-pushed the bgw/symlink-stress branch from d71635f to b84ae7d Compare January 21, 2026 18:42
@bgw bgw merged commit 917ff14 into canary Jan 21, 2026
162 of 164 checks passed
@bgw bgw deleted the bgw/symlink-stress branch January 21, 2026 21:04
bgw added a commit that referenced this pull request Jan 22, 2026
…80 on Windows (#88669)

Though I've been unable to reproduce the issue (prior PRs in this stack are my attempts at that), I believe this *should* fix the OS Error 80 ([`ERROR_FILE_EXISTS`](https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-)) that we've seen users report on Windows: #88382

Basically instead of deleting the existing link in a retry loop, and then trying to create new new link using a retry loop, we should instead:
- Merge these two retry loops into one, in case another process creates the link after we delete it. This shouldn't typically happen, but could theoretically happen.
- Extend the retry logic to also retry on [`ErrorKind::AlreadyExists`](https://github.com/rust-lang/rust/blob/503745e9170b40841611aaaa634641edffd00b29/library/std/src/sys/io/error/windows.rs#L19). This might be possible if the filesystem is eventually consistent (which can happen on Windows), but I wasn't able to reproduce this.

There's a similar -- but different -- issue that users have been reporting where they get OS Error 1 (`ERROR_INVALID_FUNCTION`) on Windows. I believe this happens if we try to create a junction point on a non-NTFS filesystem. In that case, we need to report a clearer issue to the user instead of bubbling this up as an internal Turbopack error.

I tested this on Windows with the symlink fuzzer from #88667, as well as `cargo test -p turbo-tasks-fs`:

![Screenshot 2026-01-16 at 2.16.23 PM.png](https://app.graphite.com/user-attachments/assets/5c86e09b-c5e5-4ff2-9d89-da009917a018.png)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants