{"record":{"id":"f1b883eea59dc1c2","repo":"GitoxideLabs/gitoxide","slug":"cannot-derive-commit-or-tree-from-blob-at","errorCode":null,"errorMessage":"Cannot derive commit or tree from blob at {}","messagePattern":"Cannot derive commit or tree from blob at (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitoxide-core/src/repository/archive.rs","lineNumber":91,"sourceCode":"    )?;\n\n    entries.show_throughput(start);\n    bytes.show_throughput(start);\n\n    Ok(())\n}\n\nfn fetch_rev_info(\n    object: gix::Object<'_>,\n) -> anyhow::Result<(Option<gix::date::SecondsSinceUnixEpoch>, gix::ObjectId)> {\n    Ok(match object.kind {\n        gix::object::Kind::Commit => {\n            let commit = object.into_commit();\n            (Some(commit.committer()?.seconds()), commit.tree_id()?.detach())\n        }\n        gix::object::Kind::Tree => (None, object.id),\n        gix::object::Kind::Tag => fetch_rev_info(object.peel_to_kind(gix::object::Kind::Commit)?)?,\n        gix::object::Kind::Blob => bail!(\"Cannot derive commit or tree from blob at {}\", object.id),\n    })\n}\n\nfn format_from_ext(path: &Path) -> anyhow::Result<archive::Format> {\n    Ok(match path.extension().and_then(std::ffi::OsStr::to_str) {\n        None => bail!(\"Cannot derive archive format from a file without extension\"),\n        Some(\"tar\") => archive::Format::Tar,\n        Some(\"gz\") => archive::Format::TarGz {\n            compression_level: None,\n        },\n        Some(\"zip\") => archive::Format::Zip {\n            compression_level: None,\n        },\n        Some(\"stream\") => archive::Format::InternalTransientNonPersistable,\n        Some(ext) => bail!(\"Format for extension '{ext}' is unsupported\"),\n    })\n}\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gitoxide-core/src/repository/archive.rs#L73-L109","documentation":"The archive streaming code resolves the requested revision into a commit (for the timestamp) and a tree (for contents). If the resolved object is a blob, neither can be derived, so `fetch_rev_info` bails with the blob's id. Passing a blob id as an archive source is invalid by definition.","triggerScenarios":"Calling `archive::stream` (or `fetch_rev_info`) with a revspec that resolves to a blob object, e.g. `gix archive <blob-sha>` or a spec like `HEAD:file.txt`.","commonSituations":"Copy-pasting a file/blob hash instead of a commit or tag hash; scripting revspec resolution that accidentally yields a blob path spec; typo'd ref names that fall back to object ids.","solutions":["Pass a commit-ish (branch, tag, commit sha) instead of a blob id","Resolve `HEAD:file.txt`-style specs to the containing commit before invoking archive","Verify with `gix cat <id>` or `git cat-file -t <id>` that the object is a commit or tree"],"exampleFix":"// before\ngix::archive::stream(repo, \"e1234deadbeef\" /* blob id */, out, path_fmt)?;\n// after\ngix::archive::stream(repo, \"HEAD\", out, path_fmt)?;","handlingStrategy":"validation","validationCode":"let obj = repo.rev_parse_single(rev)?.object()?;\nif obj.kind == gix::object::Kind::Blob {\n    return Err(anyhow!(\"{} is a blob; pass a commit or tree\", obj.id));\n}","typeGuard":"fn is_archivable(obj: &gix::Object<'_>) -> bool {\n    matches!(obj.kind, gix::object::Kind::Commit | gix::object::Kind::Tree | gix::object::Kind::Tag)\n}","tryCatchPattern":"match archive::stream(repo, rev, out, path) {\n    Err(e) if e.to_string().starts_with(\"Cannot derive commit or tree from blob\") => {\n        eprintln!(\"resolve a commit-ish instead of a blob id\");\n    }\n    other => other?,\n}","preventionTips":["Always verify object kind (`git cat-file -t`) before passing an id to archive","Avoid `path:file` revspecs when you want a whole-tree archive","Validate user-supplied revs resolve to commits/tags before archiving"],"tags":["git","object-model","invalid-argument"],"backgroundTag":"incompatible-source-type","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}