GitoxideLabs/gitoxide · error
Could not follow all splits after
Error message
Could not follow all splits after {round} rounds, assuming reference cycle What it means
When extending a reference transaction through splits of symbolic refs (resolving symref chains into concrete ref edits), the algorithm loops up to 5 rounds; if edits remain after round 5 it gives up with WouldBlock: 'Could not follow all splits after {round} rounds, assuming reference cycle'. It indicates symbolic references form a cycle (e.g. HEAD -> a -> b -> a), so no consistent edit set can be derived.
Solutions
- Inspect and fix the symbolic refs (`git symbolic-ref` on the chain) to break the cycle
- Delete or rewrite the offending symref files in .git/ manually if tooling can't
- Validate the repository with `git fsck` and repair or re-clone
- Ensure custom `find` implementations terminate and return real targets, not looping ones
Defensive patterns
Strategy: validation
Validate before calling
// detect symref cycles before transacting
fn resolve(head: &gix_ref::Reference, find: impl Fn(&[u8]) -> Option<gix_ref::Reference>) -> usize {
let mut seen = std::collections::HashSet::new();
let mut cur = head.clone();
while let Some(t) = cur.target().try_into().ok().and_then(|n| find(n.as_ref())) {
if !seen.insert(t.name().as_bstr().to_vec()) { return seen.len(); /* cycle */ }
cur = t;
}
seen.len()
} Prevention
- Audit symbolic refs for cycles before transactions (`git symbolic-ref -d` to break loops)
- Avoid manually editing .git symref files
- Run `git fsck` on repositories with hand-crafted refs
When it happens
Trigger: `Transaction::pre_process` calling `extend_with_splits_of_symbolic_refs` on a repository whose symbolic references form a loop longer than 5 resolution rounds, or whose `find` callback keeps returning further symref targets.
Common situations: Manually edited or corrupted symbolic refs in .git/; crafted repositories with ref-to-ref cycles; scripts that create symref chains by accident.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- a symbolic reference chain contains a cycle
- a projected worktree reference contains a symbolic cycle
- the undo queue first-parent chain contains a cycle
- A reference named ' ' has multiple edits
- BUG: tries to obtain object id from symbolic target
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/3b938e844ecf4341.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/transaction/ext.rs:107
log,
LogChange {
message: log.message.clone(),
mode: RefLog::Only,
force_create_reflog: log.force_create_reflog,
},
);
let next = std::mem::replace(expected, PreviousValue::Any);
RefEdit::update_with_log(referent, new.clone(), next, current).with_deref(true)
}
},
));
}
}
if new_edits.is_empty() {
break Ok(());
}
if round == 5 {
break Err(std::io::Error::new(
std::io::ErrorKind::WouldBlock,
format!("Could not follow all splits after {round} rounds, assuming reference cycle"),
));
}
round += 1;
first = self.len();
self.append(&mut new_edits);
}
}
}
View on GitHub (pinned to e73179060b)