GitoxideLabs/gitoxide · error
checked above
Error message
checked above
What it means
Panic from `.expect("checked above")` when processing deferred ref deletions during branch updates in gix-tix rebase. The enclosing code just matched `expected.old.is_some()` in the `defer` condition, so the expect asserts the retained value is still `Some`. It can only fire if `expected.old` was somehow mutated or the retain predicate logic changed — i.e. an internal invariant, not a user-triggerable error.
Solutions
- Verify the library version; upgrade gix-tix if this panic is reachable, as it indicates a broken invariant.
- Wrap the operation in `catch_unwind` only as a last resort; prefer reproducing and reporting the bug.
- Ensure ref-update expectations come from the library's own computation, not hand-built values with missing `old` targets.
Defensive patterns
Strategy: try-catch
Validate before calling
if expected.name == current_ref && expected.old.is_none() {
return Err(anyhow::anyhow!("cannot defer deletion of ref without known old value"));
} Type guard
fn is_deferable(e: &ExpectedRef) -> bool {
e.name == current_ref && e.old.is_some() && e.new.is_none()
} Try / catch
let out = std::panic::catch_unwind(AssertUnwindSafe(|| update_refs(...)));
if out.is_err() { anyhow::bail!("ref update panicked; report a gix-tix bug"); } Prevention
- Use only library-computed ref expectations
- Avoid deleting the checked-out branch without selecting a replacement checkout
- Upgrade gix-tix if this panic is reachable in your version
When it happens
Trigger: Calling an update/finish operation that deletes the currently checked-out branch; the panic only occurs on a code defect where the `defer` condition and the `expect` disagree about `expected.old`.
Common situations: Attempting to delete the checked-out branch as part of a rebase update while selecting another checkout; normally this path works and errors earlier with 'cannot delete the checked-out branch...'.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- valid enrich ref
- only value and unspecified are possible here
- parent-match assures this
- upper match already assured we only deal with blobs
- fixed size array with three items
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/21beb11f9dc536d0.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/rebase.rs:2219
transition.new,
)?;
}
let head = self.repo.head()?;
let unborn = head.is_unborn();
let current_ref = head.referent_name().map(ToOwned::to_owned);
let mut deferred_ref_deletions = Vec::new();
if let (Some(expected_refs), Some(current_ref)) = (&mut self.expected_refs, current_ref) {
if expected_refs
.iter()
.any(|expected| expected.name == current_ref && expected.old.is_some() && expected.new.is_none())
&& (self.repo.workdir().is_none() || (self.selected.is_none() && !self.checkout_after_finish))
{
anyhow::bail!("cannot delete the checked-out branch without selecting another checkout");
}
expected_refs.retain(|expected| {
let defer = expected.name == current_ref && expected.old.is_some() && expected.new.is_none();
if defer {
deferred_ref_deletions.push((expected.name.clone(), expected.old.expect("checked above")));
}
!defer
});
}
let updated_refs = update_refs(
&self.repo,
&self.rewritten,
unborn,
self.selected,
&self.committer,
self.expected_refs.take(),
(&self.pins, &self.delete_refs),
resource_edits,
)?;
for (transitioned, transition) in transitions.iter().enumerate() {
if let Err(err) = super::forget::apply_tree_transition(&transition.workdir, transition.old, transition.new)
{
return rollback(View on GitHub (pinned to e73179060b)