Skip to content

fix(tests): tolerate a source file vanishing during a recursive copy#36189

Open
crowlbot wants to merge 1 commit into
mainfrom
fix/spec-copy-tolerate-vanished-file
Open

fix(tests): tolerate a source file vanishing during a recursive copy#36189
crowlbot wants to merge 1 commit into
mainfrom
fix/spec-copy-tolerate-vanished-file

Conversation

@crowlbot

Copy link
Copy Markdown
Contributor

What

specs::npm::pkg_json_imports::compile intermittently panics in the test harness:

panicked at tests/util/lib/fs.rs:355:18:
called `Result::unwrap()` on an `Err` value: Copying .../.deno/npm-compat/undici-types/h2c-client.d.ts to /tmp/deno-cli-test.../.deno/npm-compat/undici-types/h2c-client.d.ts

Caused by:
    No such file or directory (os error 2)

PathRef::copy_to_recursive_with_exclusions lists a directory with read_dir and then copies each entry via PathRef::copy, which .unwrap()s the std::fs::copy result.

Why

.deno/npm-compat is a gitignored, generated cache directory (cli/tools/installer/npm_compat.rs) that ends up inside a spec's source tree as a side effect of running the spec. Specs (and the test cases within a spec) run in parallel, all copying that source tree into per-test temp dirs. When one test's recursive copy is mid-flight and another concurrently regenerates .deno/npm-compat, a file that read_dir just listed can be removed before the copy runs — std::fs::copy returns NotFound, and the .unwrap() panics, failing the test.

Fix

Add PathRef::copy_if_exists, which treats a missing source as a no-op (returns false) instead of panicking, and use it in the recursive copy. Because the entry was just returned by read_dir, a NotFound at copy time is unambiguously a concurrent removal rather than a statically missing file, so skipping it is correct. All other copy errors still panic, preserving diagnostics.

This is the same class of fix as #36138 (make the shared test infrastructure resilient to a benign parallel-execution race). A deeper follow-up would be to stop the gitignored .deno/npm-compat cache from leaking into the shared spec source tree in the first place, but that's a larger change; this removes the panic.

I can't reproduce the linux-aarch64 timing race locally, but the change turns the racy removal into a no-op instead of an unwrap panic. cargo check -p test_util passes.

Closes #36184

`PathRef::copy_to_recursive_with_exclusions` lists a directory and then copies
each entry. When specs run in parallel, a concurrent process can regenerate a
gitignored cache directory (e.g. `.deno/npm-compat`, which leaks into a spec's
source tree) and remove a file after `read_dir` listed it but before the copy.
`std::fs::copy` then fails with `NotFound` and the `.unwrap()` panicked, failing
an unrelated test (#36184).

Add `PathRef::copy_if_exists`, which treats a missing source as a no-op, and use
it in the recursive copy. Because the entry was just returned by `read_dir`, a
`NotFound` at copy time is unambiguously a concurrent removal, so skipping it is
correct; other copy errors still panic.
@crowlbot
crowlbot requested a review from crowlKats July 20, 2026 19:50
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.

flaky: specs::npm::pkg_json_imports::compile fails copying npm-compat cache file (No such file or directory)

1 participant