{"record":{"id":"b5f95f2a85bcd65a","repo":"GitoxideLabs/gitoxide","slug":"tix-stash-reference-does-not-use-a-canonical-full","errorCode":null,"errorMessage":"tix stash reference does not use a canonical full commit ID","messagePattern":"tix stash reference does not use a canonical full commit ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/stash.rs","lineNumber":36,"sourceCode":"use crate::open_repository;\n\npub(crate) fn reference(id: ObjectId) -> Result<gix::refs::FullName> {\n    format!(\n        \"{}{}\",\n        String::from_utf8_lossy(crate::history::STASH_PREFIX),\n        id.to_hex()\n    )\n    .try_into()\n    .context(\"generated an invalid tix stash reference\")\n}\n\npub(crate) fn associated_commit(name: &BStr) -> Result<Option<ObjectId>> {\n    let Some(suffix) = name.strip_prefix(crate::history::STASH_PREFIX) else {\n        return Ok(None);\n    };\n    let id = ObjectId::from_hex(suffix).context(\"tix stash reference has an invalid commit ID\")?;\n    if id.to_hex().to_string().as_bytes() != suffix {\n        anyhow::bail!(\"tix stash reference does not use a canonical full commit ID\");\n    }\n    Ok(Some(id))\n}\n\npub(super) struct RewriteEdits {\n    pub forward: Vec<RefEdit>,\n    pub rollback: Vec<RefEdit>,\n}\n\npub(super) fn rewrite_edits(\n    repo: &gix::Repository,\n    rewritten: &HashMap<ObjectId, Option<ObjectId>>,\n    removed: &HashSet<ObjectId>,\n) -> Result<RewriteEdits> {\n    let mut moves = Vec::new();\n    let mut destinations = HashMap::<ObjectId, ObjectId>::new();\n    for reference in repo.references()?.all()? {\n        let reference = match reference {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/stash.rs#L18-L54","documentation":"Tix saves worktree state under synthetic references named after a stash prefix plus a full commit ID. This error fires when the text after the prefix does not parse back to a hex ID that re-serializes byte-for-byte identically — i.e. the ID is not written in canonical lowercase full-length form. `associated_commit` parses the suffix and compares `id.to_hex()` against the raw suffix bytes.","triggerScenarios":"Calling `edit::stash::associated_commit` with a reference name whose suffix is uppercase hex, abbreviated (short) hex, contains leading zeros removed, or is otherwise not exactly 40/64 lowercase hex characters after `STASH_PREFIX`.","commonSituations":"Hand-renaming or scripting stash references with shortened IDs; copying IDs from a UI that uppercases hex; older tix versions or external tools writing differently formatted stash refs.","solutions":["Rewrite the reference name using the canonical lowercase full-length hex encoding of the commit ID","Recompute the expected name with `reference(id)` instead of hand-building it","Delete or rename the malformed stash reference and re-create it via the tix stash command"],"exampleFix":"// before\nlet name = format!(\"{STASH_PREFIX}aBc123\");\n// after\nlet id = ObjectId::from_hex(b\"abc123...\")?;\nlet name = reference(id)?; // canonical full hex form","handlingStrategy":"validation","validationCode":"fn is_canonical_stash_name(name: &BStr) -> bool {\n    match name.strip_prefix(tix::history::STASH_PREFIX) {\n        Some(suffix) => match ObjectId::from_hex(suffix) {\n            Ok(id) => id.to_hex().to_string().as_bytes() == suffix,\n            Err(_) => false,\n        },\n        None => false,\n    }\n}","typeGuard":"fn canonical_stash_id(name: &BStr) -> Option<ObjectId> {\n    let suffix = name.strip_prefix(tix::history::STASH_PREFIX)?;\n    let id = ObjectId::from_hex(suffix).ok()?;\n    (id.to_hex().to_string().as_bytes() == suffix).then_some(id)\n}","tryCatchPattern":"match stash::associated_commit(name) {\n    Ok(Some(id)) => use_stash(id),\n    Ok(None) => {} /* not a tix stash ref */,\n    Err(e) if e.to_string().contains(\"canonical full commit ID\") => repair_reference_name(name),\n    Err(e) => return Err(e),\n}","preventionTips":["Always build stash reference names with `stash::reference(id)`, never by hand","Never abbreviate or uppercase hex IDs in reference names","Treat tix stash refs as opaque; don't rename them in scripts"],"tags":["git","references","hex-format","stash"],"backgroundTag":"invalid-identifier-format","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}