rust-lang/cargo · error

path ` ` is not a blob in the git repo

Error message

path `{}` is not a blob in the git repo

What it means

When reading a file from a git-backed registry index, Cargo looked up the tree entry for `path`, retrieved the git object, but the object was not a blob (e.g. it was a tree, commit, or tag). The index format requires each crate's metadata to be stored as a blob file, so a non-blob indicates a corrupt or non-standard index repository.

Solutions

  1. Re-clone the registry index: remove `~/.cargo/registry/index/<name>` and run `cargo fetch`.
  2. If you operate the private registry, inspect the index repo with `git ls-tree` and replace any non-blob entry at the offending path with a proper blob file.
  3. Verify the registry index follows the crates.io index layout (one file per crate under the hashed prefix).

Example fix

# inspect the offending object in a private index
$ git --git-dir ~/.cargo/registry/git/index ls-tree HEAD <path>
# if it shows `tree` instead of `blob`, fix the upstream index, then:
$ rm -rf ~/.cargo/registry/index/<name> && cargo fetch
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the index object type before assuming blob.
fn assert_blob(repo: &git2::Repository, tree: &git2::Tree, path: &Path) -> Result<(), anyhow::Error> {
    let entry = tree.get_path(path)?;
    let obj = entry.to_object(repo)?;
    if obj.as_blob().is_none() {
        anyhow::bail!("not a blob: {}", path.display());
    }
    Ok(())
}

Type guard

fn is_blob(repo: &git2::Repository, tree: &git2::Tree, path: &std::path::Path) -> bool {
    tree.get_path(path).ok()
        .and_then(|e| e.to_object(repo).ok())
        .map_or(false, |o| o.as_blob().is_some())
}

Try / catch

match load_helper(self, path, index_version) {
    Ok(r) => Ok(r),
    Err(e) if e.to_string().contains("not a blob") => { /* re-clone index */ reclone_index()?; load_helper(self, path, index_version) }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Inside `git_remote.rs` `load_helper`, after `tree.get_path(path)` resolves and `entry.to_object(repo)` succeeds, `object.as_blob()` returns `None`. Happens when the registry index git repo contains a directory (tree) or other object type where a blob is expected.

Common situations: Corrupted or hand-edited private registry index repository; an index repo where a crate path was replaced by a directory; partial clone/fetch that left an incomplete object; filesystem case-collision on case-insensitive volumes turning a file into a dir entry.

Related errors


AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11). Data as JSON: /api/errors/7861add82028a269. Report an issue: GitHub.

Appendix: source

Thrown at src/sources/registry/git_remote.rs:356

            registry: &GitRegistry<'_>,
            path: &Path,
            index_version: Option<&str>,
        ) -> CargoResult<LoadResponse> {
            let repo = registry.repo()?;
            let repo = repo.as_ref().unwrap();
            let tree = registry.tree()?;
            let entry = tree.get_path(path);
            let entry = entry?;
            let git_file_hash = Some(entry.id().to_string());

            // Check if the cache is valid.
            if index_version.is_some() && index_version == git_file_hash.as_deref() {
                return Ok(LoadResponse::CacheValid);
            }

            let object = entry.to_object(repo)?;
            let Some(blob) = object.as_blob() else {
                anyhow::bail!("path `{}` is not a blob in the git repo", path.display())
            };

            Ok(LoadResponse::Data {
                raw_data: blob.content().to_vec(),
                index_version: git_file_hash,
            })
        }

        loop {
            return match load_helper(&self, path, index_version) {
                Ok(result) => Ok(result),
                Err(_) if !self.is_updated() => {
                    // If git returns an error and we haven't updated the repo,
                    // return pending to allow an update to try again.
                    self.needs_update.set(true);
                    self.update()?;
                    continue;
                }

View on GitHub (pinned to eb98b54bc9)