{"record":{"id":"644670a91890a4b0","repo":"GitoxideLabs/gitoxide","slug":"the-recorded-head-ref-is-not-editable","errorCode":null,"errorMessage":"the recorded HEAD ref is not editable","messagePattern":"the recorded HEAD ref is not editable","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/edit/todo.rs","lineNumber":802,"sourceCode":"    if state.tips.iter().copied().collect::<HashSet<_>>().len() != state.tips.len() {\n        anyhow::bail!(\"the rebase state contains duplicate tips\");\n    }\n    let mut refs = HashSet::new();\n    for reference in &state.expected_refs {\n        if !refs.insert(reference.name.as_bstr()) {\n            anyhow::bail!(\"the rebase state contains duplicate refs\");\n        }\n        if !scope.contains(&reference.target) && reference.target != state.base && reference.target != state.onto {\n            anyhow::bail!(\"a captured ref does not logically point into the rebase scope\");\n        }\n    }\n    if let Some(name) = &state.head_ref\n        && !state\n            .expected_refs\n            .iter()\n            .any(|reference| reference.editable && reference.name == *name)\n    {\n        anyhow::bail!(\"the recorded HEAD ref is not editable\");\n    }\n    for tip in &state.tips {\n        repo.find_commit(*tip).context(\"could not find a recorded rebase tip\")?;\n    }\n    for id in &state.scope {\n        let commit = repo\n            .find_commit(*id)\n            .context(\"could not find a recorded scope commit\")?;\n        let parent = commit\n            .parent_ids()\n            .next()\n            .map(gix::Id::detach)\n            .context(\"a recorded scope commit has no parent\")?;\n        if parent != state.base && !scope.contains(&parent) && !continuation_sources.contains(id) {\n            anyhow::bail!(\"a recorded scope commit is disconnected from the rebase base\");\n        }\n    }\n    if state.resolved.is_some_and(|id| !scope.contains(&id)) {","sourceCodeStart":784,"sourceCodeEnd":820,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/edit/todo.rs#L784-L820","documentation":"The rebase state records a HEAD ref name, but validation requires that this name appears among the expected refs flagged as `editable`. If the recorded HEAD ref is missing from expected_refs or is not editable, the state cannot safely move HEAD during the rebase, so it is rejected.","triggerScenarios":"Parsing a rebase state where `state.head_ref` is Some but no entry in `state.expected_refs` has `editable == true` and a matching name. Caused by hand-edited state files, partially written state, or state from a different tix version.","commonSituations":"Editing the state file to rename HEAD; state files produced by incompatible tix versions; truncated state writes after a crash.","solutions":["Discard the stale rebase state and restart the rebase","Ensure the HEAD ref name recorded in the state matches an expected ref marked editable","Regenerate state with the same tix version that started the rebase"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if let Some(name) = &state.head_ref {\n    assert!(state.expected_refs.iter().any(|r| r.editable && r.name == *name),\n        \"HEAD ref must be listed as an editable expected ref\");\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = result {\n    if e.to_string().contains(\"HEAD ref is not editable\") {\n        // treat state as corrupt: abandon and restart rebase\n    }\n}","preventionTips":["Only modify rebase state with tix itself","Keep the same tix version for start and resume of a rebase","Verify state completeness after crashes before resuming"],"tags":["rebase","state-validation","head-ref"],"backgroundTag":"invalid-state-transition","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"}