rust-lang/cargo · error
registry said cache valid when no cache exists
Error message
registry said cache valid when no cache exists
What it means
The registry backend returned `LoadResponse::CacheValid` (meaning the client's cached `index_version` is still current), but the caller had no in-memory `cached_summaries` to return. This is an internal invariant violation: the backend should not claim a cache is valid when the index layer holds nothing to validate against.
Solutions
- Clear the entire registry index cache: `rm -rf ~/.cargo/registry/index/<name>` then `cargo fetch`.
- If operating a private registry, ensure it returns `404`/data (not `304 Not Modified`) when the client supplies an `index_version` it never received data for.
- Update Cargo — this often indicates a bug fixed in newer versions.
- Report with `--verbose` logs if it reproduces on the latest Cargo.
Example fix
# before: desync between version tracker and cache body $ cargo build error: registry said cache valid when no cache exists # after: full index reset $ rm -rf ~/.cargo/registry/index/<name> $ cargo fetch
Defensive patterns
Strategy: try-catch
Validate before calling
// Caller-side: only pass index_version when we actually have cached data. let version_to_send = cached_summaries.as_ref().and_then(|_| index_version.as_deref()); let resp = load.load(root, relative.as_ref(), version_to_send).await?;
Type guard
fn cache_state_consistent(cached: &Option<Summaries>, resp: &LoadResponse) -> bool {
!matches!(resp, LoadResponse::CacheValid) || cached.is_some()
} Try / catch
match response {
LoadResponse::CacheValid if cached_summaries.is_none() => {
// recover: invalidate and re-load unconditionally
cache_manager.invalidate(lowered_name);
self.load_summaries(name, load).await
}
other => /* normal handling */,
}; Prevention
- Treat `CacheValid` without local data as a signal to re-fetch, not a fatal error.
- Don't partially delete cache files; clear the whole index dir.
- Keep private registry backends correct about 304 semantics.
- Upgrade Cargo to pick up invariant-recovery fixes.
When it happens
Trigger: In `load_summaries`, after `cache_manager.get(lowered_name)` failed to parse (or returned nothing) so `cached_summaries` is `None`, yet the remote responded with `CacheValid`. Indicates a logic bug, a cache/index state desync, or a registry server incorrectly returning 304/Not-Modified for content the client never had.
Common situations: Corrupt local cache that failed to parse (so `cached_summaries` is None) combined with a server returning a cache-valid signal; race between cache invalidation and load; bug in a custom registry backend; partial cache after a manual `rm` of cache files but not the version tracker.
Related errors
- cache expected 4 bytes for index schema version
- override found but no real ones
- cannot publish with `open-namespaces`
- config.json not found
- failed to read path
AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11).
Data as JSON: /api/errors/fc7c558b3f71cfcf.
Report an issue: GitHub.
Appendix: source
Thrown at src/sources/registry/index/mod.rs:556
Ok((s, v)) => {
cached_summaries = Some(s);
index_version = Some(v);
}
Err(e) => {
tracing::debug!("failed to parse {lowered_name:?} cache: {e}");
}
}
}
let response = load
.load(root, relative.as_ref(), index_version.as_deref())
.await?;
match response {
LoadResponse::CacheValid => {
tracing::debug!("fast path for registry cache of {:?}", relative);
if cached_summaries.is_none() {
return Err(anyhow::anyhow!(
"registry said cache valid when no cache exists"
));
}
return Ok(cached_summaries);
}
LoadResponse::NotFound => {
cache_manager.invalidate(lowered_name);
return Ok(None);
}
LoadResponse::Data {
raw_data,
index_version,
} => {
// This is the fallback path where we actually talk to the registry backend to load
// information. Here we parse every single line in the index (as we need
// to find the versions)
tracing::debug!("slow path for {:?}", relative);
let mut cache = SummariesCache::default();View on GitHub (pinned to 98a09e7e7d)