fix(install): handle ETXTBSY when setting up node_modules#33311
fix(install): handle ETXTBSY when setting up node_modules#33311bartlomieju wants to merge 1 commit intomainfrom
Conversation
When `nodeModulesDir: "auto"` is used, Deno creates hardlinks from the
global npm cache to `node_modules/.deno/`. If a binary (like esbuild) is
currently executing from one of these hardlinks, attempts to overwrite
the file fail with ETXTBSY ("text file busy") on Linux.
This manifests as "Text file busy (os error 26)" errors during
vite/vitepress builds, especially in containers (Podman/Docker), CI, and
when the LSP or a dev server is running alongside.
The fix handles ETXTBSY in the copy fallback paths by removing the
destination file before retrying the copy. Removing the file (unlink)
breaks the hardlink and allows the copy to create a new inode that
doesn't conflict with the executing process.
Closes #30424
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| // The destination is a hardlink to a currently-executing | ||
| // binary (ETXTBSY). Remove it to break the hardlink, then | ||
| // retry the copy. | ||
| let _ = sys.fs_remove_file(&new_to); |
There was a problem hiding this comment.
Problem: the ETXTBSY recovery path ignores fs_remove_file errors before retrying the copy.
Why here: in both fallback paths we do let _ = sys.fs_remove_file(&new_to); and then immediately retry fs_copy. If the unlink fails for a reason other than "already gone" (permissions, read-only fs, unexpected race), we silently discard the more informative error and only surface whatever the second copy returns.
Impact: that can make ETXTBSY-related setup failures harder to diagnose, especially on the container / overlayfs configurations this PR is targeting.
Ask: would it make sense to only ignore NotFound here and otherwise return the unlink error directly? That would still handle the intended race while preserving better failure information for the weird cases.
nathanwhit
left a comment
There was a problem hiding this comment.
I'm not super convinced it will fix anything, but seems ok to me
Summary
Fixes ETXTBSY ("Text file busy", OS error 26) errors when using
nodeModulesDir: "auto"on Linux, especially in containers (Podman), CI, WSL2, and when the LSP or a dev server is running alongside.Root cause: With
nodeModulesDir: "auto", Deno creates hardlinks from the global npm cache tonode_modules/.deno/. When a binary (like esbuild) is executing from one of these hardlinks, any attempt to write to the same inode fails with ETXTBSY. This affects:deno installwhile another Deno process is runningFix: When a copy operation encounters ETXTBSY, remove the destination file first (breaking the hardlink), then retry.
unlink()works on executing files — it removes the directory entry while the process keeps the inode alive — so the retry creates a fresh inode.Three locations are patched:
copy_dir_recursive()— the fallback whenhard_link_dir_recursivefailsclone_dir_recursive_except_node_modules_child()— individual file hardlink-or-copy in local.rsis_etxtbsy()helper todeno_npm_cacheCloses #30424
Test plan
cargo checkpassescargo clippy --all-targetscleancargo test -p deno_npm_cache -p deno_npm_installerpasses🤖 Generated with Claude Code