rust-lang/cargo · error · anyhow::Error

cache expected 4 bytes for index schema version

Error message

cache expected 4 bytes for index schema version

What it means

When parsing the on-disk `SummariesCache` for a crate (src/sources/registry/index/cache.rs:165), Cargo reads a 1-byte version header then expects at least 4 more bytes encoding the little-endian `u32` index schema version. If the file is truncated to fewer than 5 bytes total (`rest.get(..4)` is `None`), it bails. This indicates a corrupt or partially-written cache entry.

Source

Thrown at src/sources/registry/index/cache.rs:175

    pub versions: Vec<(Version, &'a [u8])>,
    /// For cache invalidation, we tracks the index file version to determine
    /// when to regenerate the cache itself.
    pub index_version: &'a str,
}

impl<'a> SummariesCache<'a> {
    /// Deserializes an on-disk cache.
    pub fn parse(data: &'a [u8]) -> CargoResult<SummariesCache<'a>> {
        // NB: keep this method in sync with `serialize` below
        let (first_byte, rest) = data
            .split_first()
            .ok_or_else(|| anyhow::format_err!("malformed cache"))?;
        if *first_byte != CURRENT_CACHE_VERSION {
            bail!("looks like a different Cargo's cache, bailing out");
        }
        let index_v_bytes = rest
            .get(..4)
            .ok_or_else(|| anyhow::anyhow!("cache expected 4 bytes for index schema version"))?;
        let index_v = u32::from_le_bytes(index_v_bytes.try_into().unwrap());
        if index_v != INDEX_V_MAX {
            bail!(
                "index schema version {index_v} doesn't match the version I know ({INDEX_V_MAX})",
            );
        }
        let rest = &rest[4..];

        let mut iter = split(rest, 0);
        let last_index_update = if let Some(update) = iter.next() {
            str::from_utf8(update)?
        } else {
            bail!("malformed file");
        };
        let mut ret = SummariesCache::default();
        ret.index_version = last_index_update;
        while let Some(version) = iter.next() {
            let version = str::from_utf8(version)?;

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Clear the affected cache: `rm -rf ~/.cargo/registry/index/*/.cache/` and let Cargo regenerate it.
  2. If it recurs, check for disk-full conditions, antivirus, or cloud-sync tools touching `~/.cargo`.
  3. Run `cargo cache --autoclean` (if cargo-cache is installed) or a full `cargo clean`.

Example fix

# before: corrupt cache blocks every build
rm -rf ~/.cargo/registry/index/*/.cache/
cargo fetch
Defensive patterns

Strategy: fallback

Validate before calling

// Before trusting a cache file, sanity-check its length.
fn cache_looks_complete(data: &[u8]) -> bool {
    data.len() >= 5 // 1 version byte + 4 schema-version bytes
}

Try / catch

// On parse failure, delete and regenerate rather than crash.
match SummariesCache::parse(&data) {
    Ok(c) => c,
    Err(_) => { fs::remove_file(&cache_path).ok(); /* force refetch */ bail!("cache corrupt, removed"); }
}

Prevention

When it happens

Trigger: A cache file under `~/.cargo/registry/index/<reg>/.cache/` that was truncated by a crash/power loss mid-write, a filesystem with 512-byte sector corruption, or an external tool that emptied/truncated the file. Reached on any operation that loads a cached crate summary.

Common situations: Build interrupted by SIGKILL/OOM while Cargo was rewriting the cache; antivirus or sync tools (Dropbox/OneDrive) truncating files in `~/.cargo`; disk full at write time; upgrading Cargo across a cache-format change with a half-written file.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/eb3775ea10661801.json. Report an issue: GitHub.