{"record":{"id":"5b449384cdd17b63","repo":"GitoxideLabs/gitoxide","slug":"the-undo-queue-records-itself","errorCode":null,"errorMessage":"the undo queue records itself","messagePattern":"the undo queue records itself","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/undo.rs","lineNumber":621,"sourceCode":"    ensure_exact_keys(&undo, &[\"version\"])?;\n    ensure!(\n        undo.value(\"version\").as_ref().map(|value| value.as_slice()) == Some(VERSION.as_bytes()),\n        \"unsupported undo metadata version\"\n    );\n\n    let mut changes = Vec::new();\n    let mut previous_name: Option<FullName> = None;\n    for section in sections {\n        ensure!(\n            section.header().name() == b\"ref\",\n            \"undo metadata contains an unknown section\"\n        );\n        let subsection = section\n            .header()\n            .subsection_name()\n            .context(\"an undo ref section has no reference name\")?;\n        let name = FullName::try_from(subsection).context(\"an undo entry contains an invalid reference name\")?;\n        ensure!(!is_queue_ref(name.as_bstr()), \"the undo queue records itself\");\n        if let Some(previous) = &previous_name {\n            ensure!(\n                previous < &name,\n                \"undo reference sections are duplicated or out of order\"\n            );\n        }\n        previous_name = Some(name.clone());\n        ensure_exact_keys(&section, &[\"before\", \"after\"])?;\n        let before = section.value(\"before\").context(\"an undo ref has no before-state\")?;\n        let before = parse_state(repo, before.as_bstr())?;\n        let after = section.value(\"after\").context(\"an undo ref has no after-state\")?;\n        let after = parse_state(repo, after.as_bstr())?;\n        ensure!(before != after, \"an undo ref does not change\");\n        changes.push(RefChange { name, before, after });\n    }\n    Ok(changes)\n}\n","sourceCodeStart":603,"sourceCodeEnd":639,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/undo.rs#L603-L639","documentation":"The undo metadata must never contain an entry for the undo queue ref itself; the queue records changes to other references only. `parse_config` rejects any `[ref \"...\"]` section whose reference name is the queue ref (as detected by `is_queue_ref`), preventing recursive/self-referential undo state that would corrupt undo/redo semantics.","triggerScenarios":"Parsing undo metadata that contains a section like `[ref \"refs/tix/undo/queue\"]` — possible if a ref change targeting the queue was serialized by a buggy or tampered-with writer, or if the queue ref was renamed/repointed manually.","commonSituations":"Hand-editing the undo metadata, custom scripts writing tix refs, or an older/patched tix build that failed to exclude the queue ref when recording changes.","solutions":["Remove the `[ref \"...\"]` section whose name matches the undo queue ref from the metadata","Re-record the undo state by re-running the tix operation so it is regenerated correctly","Verify no script or hook writes changes to the queue ref into undo metadata","Update to a tix version that filters the queue ref when serializing"],"exampleFix":"// before\n[undo]\n\tversion = v1\n[ref \"refs/tix/undo/queue\"]\n\tbefore = missing\n\tafter = object:def456\n// after (queue section removed)\n[undo]\n\tversion = v1\n[ref \"refs/heads/main\"]\n\tbefore = missing\n\tafter = object:abc123","handlingStrategy":"validation","validationCode":"// detect a self-referential queue entry before parsing\nlet queue_ref = \"refs/tix/undo/queue\";\nlet config = gix::config::File::try_from(body.as_ref())?;\nfor s in config.sections() {\n    if s.header().name() == b\"ref\" {\n        let name = s.header().subsection_name().unwrap_or_default();\n        assert!(name != queue_ref, \"undo queue records itself\");\n    }\n}","typeGuard":"fn is_queue_ref(name: &bstr::BStr) -> bool {\n    name.starts_with(b\"refs/tix/undo/\")\n}","tryCatchPattern":"match parse_undo_metadata(&repo, &body) {\n    Ok(changes) => changes,\n    Err(e) if e.to_string().contains(\"records itself\") => {\n        eprintln!(\"self-referential undo state; rebuilding\");\n        rebuild_undo_state(&repo)?\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Exclude the queue ref when writing undo metadata","Avoid custom scripts that write tix refs directly","Regenerate undo state rather than patching it by hand","Keep tix updated so writer-side filtering bugs are fixed"],"tags":["git","undo","validation"],"backgroundTag":"invalid-config-value","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"}