npm: --cached-only fails with "npm package not found in cache" when the cache holds abbreviated metadata without time
## Summary
`--cached-only` fails with a misleading error when the npm cache holds abbreviated install-manifest metadata (written by an older Deno, e.g. 2.8.x), even though the package metadata and contents are fully cached.
Since 2.9, the default `minimumDependencyAge` policy (24h) requires publication timestamps, so Deno requests full packuments. A cached abbreviated packument has no per-version `time` data, so Deno decides it must re-fetch the full packument. Under `--cached-only` that network request is forbidden, and instead of falling back to the usable cached metadata it reports:
```
error: Failed loading http://localhost:4260/@denotest%2fesm-basic for package "@denotest/esm-basic"
0: npm package not found in cache: "@denotest/esm-basic", --cached-only is specified.
```
The package *is* in the cache; only the optional publication timestamps are missing. The resolver already treats a missing publish timestamp as acceptable (`matches_newest_dependency_date` fails open), so the cached metadata is fully usable for resolution.
This is a backward-compatibility regression: artifacts built and cached with Deno <= 2.8.x deterministically fail to start on 2.9.x with `--cached-only`, before any application code runs (this caused a Deno Deploy incident).
## Reproduction
1. Populate a cache with the abbreviated packument (policy disabled):
`deno run --no-lock --minimum-dependency-age=0 main.ts` where `main.ts` contains `import "npm:@denotest/esm-basic";`
2. Simulate a cache written by an older Deno: remove the `time` field (and `_deno.packumentFormat` marker if present) from `<DENO_DIR>/npm/<registry>/@denotest/esm-basic/registry.json` (an unmodified abbreviated cache already lacks both).
3. Run with the default policy and `--cached-only`:
`deno run --no-lock --cached-only --minimum-dependency-age=1440 main.ts`
Expected: resolves from the cache and prints `ok`.
Actual: exits 1 with `npm package not found in cache: "@denotest/esm-basic", --cached-only is specified.`
## Cause
In `libs/npm_cache/registry_info.rs`, when cached metadata has empty `time` and no `_deno.packumentFormat` marker, the code falls through to re-fetch the full packument; under `NpmCacheSetting::Only` this then errors instead of returning the cached info:
```
cached metadata lacks timestamps -> prepare to refetch
cached_only -> "package not found in cache"
```
"cached metadata + optional upgrade + offline" is incorrectly collapsed into "not cached".
## Suggested fix
Only attempt the full-packument re-fetch when networking is permitted (`cache_setting != Only`); otherwise use the cached abbreviated metadata as-is. Online behavior (timestamp enforcement) stays unchanged.
A regression spec test (`tests/specs/npm/cached_only_old_abbreviated_metadata`) has been prepared and verified: it fails on current main with the error above and passes with the fix.
## Related issues
- #35761 / #35834 — don't re-fetch packuments when the registry provides no `time` data (introduced the `_deno.packumentFormat` marker used in the faulty condition)
- #35051 — avoid spurious npm re-resolution that fails under `--cached-only`
- #35901 / #35903 — `--cached-only` error when registry info for a deprecated package is missing from the cache (fixed, but only avoids triggering the fetch when it is unnecessary; it doesn't help when resolution from cached metadata is actually needed, which is the case here)
- #35285 — slim cached full packument when `minimumDependencyAge` is set
- #32364 — request abbreviated packuments from the npm registry (the change that produced the older-format caches)
## Environment
- Deno 2.9.x (regression vs 2.8.x caches)
- `--cached-only` + default `minimumDependencyAge` (24h)
0 条评论