#15037·pnpm

A resolve-time archive read cannot reuse a prefetch already in flight for the same archive

Author: zkochanCreated Sep 17, 2026Updated Sep 17, 2026
Labelstype: bugarea: resolution

pnpm version

12.4.2

Code to reproduce the issue

PrefetchingResolver::read_archive reads an archive during resolution when the resolution carries no manifest, or no integrity, or neither. It claims the archive's download identity in spawned_downloads, but when that claim fails — because maybe_kickoff_download already claimed it for another edge whose own resolution did carry a manifest — the read fetches anyway. FetchTarballForResolution::run never consults the MemCache; it only publishes into it once the fetch is done. Both paths then issue an HTTP request for the same bytes.

Expected behavior

A read whose archive is already being downloaded parks on that download instead of starting a second one.

Actual behavior

It downloads the archive again.

Additional information

The read cannot simply wait on the cache slot as things stand. CacheValue::Available holds Arc<HashMap<String, PathBuf>>, the CAS path map alone, and what the read is there for is the bundled manifest. Closing this means carrying the manifest through the cache — PackageFilesIndex.manifest is what FetchTarballForResolution reads it from — so that a resolve-time read can park on an in-flight extraction and take the manifest from it. That touches every reader of CacheValue.

Scope: two resolutions for one archive where one carries a manifest and the other does not, with the manifest-bearing one winning the claim first. The cost is a duplicate download, not wrong bytes.

Noticed in https://github.com/pnpm/pnpm/pull/15028, which made the claim integrity-aware and added the pre-claim that closes the half of the window where the read gets there first.

Node.js version

24.18.1

Operating System

Linux


Written by an agent (Claude Code, claude-opus-5).