{"id":"fc7c558b3f71cfcf","repo":"rust-lang/cargo","slug":"registry-said-cache-valid-when-no-cache-exists","errorCode":null,"errorMessage":"registry said cache valid when no cache exists","messagePattern":"registry said cache valid when no cache exists","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/sources/registry/index/mod.rs","lineNumber":555,"sourceCode":"                Ok((s, v)) => {\n                    cached_summaries = Some(s);\n                    index_version = Some(v);\n                }\n                Err(e) => {\n                    tracing::debug!(\"failed to parse {lowered_name:?} cache: {e}\");\n                }\n            }\n        }\n\n        let response = load\n            .load(root, relative.as_ref(), index_version.as_deref())\n            .await?;\n\n        match response {\n            LoadResponse::CacheValid => {\n                tracing::debug!(\"fast path for registry cache of {:?}\", relative);\n                if cached_summaries.is_none() {\n                    return Err(anyhow::anyhow!(\n                        \"registry said cache valid when no cache exists\"\n                    ));\n                }\n                return Ok(cached_summaries);\n            }\n            LoadResponse::NotFound => {\n                cache_manager.invalidate(lowered_name);\n                return Ok(None);\n            }\n            LoadResponse::Data {\n                raw_data,\n                index_version,\n            } => {\n                // This is the fallback path where we actually talk to the registry backend to load\n                // information. Here we parse every single line in the index (as we need\n                // to find the versions)\n                tracing::debug!(\"slow path for {:?}\", relative);\n                let mut cache = SummariesCache::default();","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/sources/registry/index/mod.rs#L537-L573","documentation":"When loading a crate summary, Cargo first checks its on-disk cache and sends the cached `index_version` to the backend; if the backend responds `LoadResponse::CacheValid` (meaning 'your cache is current') but Cargo has no cached summary at all, it bails (src/sources/registry/index/mod.rs:552). A backend must only claim cache-validity relative to a version the client actually holds.","triggerScenarios":"A registry backend (`load` impl) returns `CacheValid` while the caller's `cached_summaries` is `None` — i.e. an inconsistency between 'do you have a cache?' and 'is it valid?'. Typically a bug in a custom `RegistryData` implementation, or a state-machine glitch where the cache file was deleted between the version check and the load.","commonSituations":"Custom/alternative registry backends with a buggy `load()` that returns `CacheValid` unconditionally; concurrent processes deleting the cache file mid-operation; a corrupt cache that failed to parse (so `cached_summaries` is None) yet the backend still says valid.","solutions":["Delete the registry cache for that crate/registry and retry: `rm -rf ~/.cargo/registry/index/<reg>/`.","If you maintain a custom `RegistryData` impl, only return `CacheValid` when you were actually passed a non-`None` `index_version` AND you can confirm the client holds that version.","Ensure no other process is mutating `~/.cargo/registry/` concurrently (Cargo uses file locks; external cleaners bypass them)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Custom RegistryData impls: only claim CacheValid when a cache actually exists.\nasync fn load(&self, root: &Path, path: &Path, index_version: Option<&str>) -> CargoResult<LoadResponse> {\n    if let Some(v) = index_version {\n        if !self.cache_exists(path)? { return Ok(LoadResponse::Data { /* ... */ }); }\n        if v == self.server_version(path)? { return Ok(LoadResponse::CacheValid); }\n    }\n    // ... fetch fresh\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only return `LoadResponse::CacheValid` when the caller passed a non-None index_version AND a local cache is present.","Don't delete cache files out from under a running cargo (use cargo's own cache commands)."],"tags":["cargo","registry","cache","validation","internal"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}