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

unable to read .cargo-ok file at {path:?}: {e}

Error message

unable to read .cargo-ok file at {path:?}: {e}

What it means

Before unpacking a `.crate`, Cargo reads its `.cargo-ok` marker file (src/sources/registry/mod.rs:562). A `NotFound` IO error is expected and ignored (meaning 'unpack fresh'), but any *other* IO error (permission denied, disk error, broken symlink) is fatal and reported with this message including `{path:?}` and the underlying `{e}`. This protects against silently treating an unreadable cache as 'not yet unpacked'.

Source

Thrown at src/sources/registry/mod.rs:585

                        .mark_registry_src_used(global_cache_tracker::RegistrySrc {
                            encoded_registry_name: self.name,
                            package_dir: package_dir.into(),
                            size: None,
                        });
                    return Ok(unpack_dir.to_path_buf());
                }
                _ => {
                    if ok == "ok" {
                        tracing::debug!("old `ok` content found, clearing cache");
                    } else {
                        tracing::warn!("unrecognized .cargo-ok content, clearing cache: {ok}");
                    }
                    // See comment of `unpack_package` about why removing all stuff.
                    paths::remove_dir_all(dst.as_path_unlocked())?;
                }
            },
            Err(e) if e.kind() == io::ErrorKind::NotFound => {}
            Err(e) => anyhow::bail!("unable to read .cargo-ok file at {path:?}: {e}"),
        }
        dst.create_dir()?;

        let bytes_written = unpack(self.gctx, tarball, unpack_dir, &|_| true)?;
        update_mtime_for_generated_files(unpack_dir);

        // Now that we've finished unpacking, create and write to the lock file to indicate that
        // unpacking was successful.
        let mut ok = OpenOptions::new()
            .create_new(true)
            .read(true)
            .write(true)
            .open(&path)
            .with_context(|| format!("failed to open `{}`", path.display()))?;

        let lock_meta = LockMetadata { v: 1 };
        write!(ok, "{}", serde_json::to_string(&lock_meta).unwrap())?;

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Inspect the exact `{path}` from the message and check permissions/ownership: `ls -la <dir>`.
  2. Fix ownership/permissions (`chown`/`chmod`) or remove the corrupted unpacked package directory so Cargo re-unpacks.
  3. If the disk/filesystem is failing, run `fsck` / move `CARGO_HOME` to healthy storage.

Example fix

# before: .cargo-ok unreadable (wrong owner)
sudo chown -R $USER:$USER ~/.cargo
# or just evict the bad unpack
cargo cache --autoclean  # / rm -rf ~/.cargo/registry/src/<reg>/<pkg>-<ver>
Defensive patterns

Strategy: validation

Validate before calling

// If you manipulate ~/.cargo programmatically, ensure .cargo-ok is readable.
fn cargo_ok_readable(p: &Path) -> bool {
    match std::fs::read_to_string(p) {
        Ok(_) => true,
        Err(e) if e.kind() == std::io::ErrorKind::NotFound => true, // expected
        Err(_) => false,
    }
}

Prevention

When it happens

Trigger: The `.cargo-ok` file exists but can't be read due to permissions (`EACCES`), a broken symlink, a filesystem I/O error, or a race where the file/dir was removed mid-operation with a non-NotFound error.

Common situations: `chmod`/ownership changes under `~/.cargo/registry/src/`; a broken symlink left by a failed sync; disk/filesystem corruption; SELinux/AppArmor denying reads; running as a different user than the one that created the cache.

Related errors


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