GitoxideLabs/gitoxide · error
history traversal did not produce a graph
Error message
history traversal did not produce a graph
What it means
A history traversal is expected to emit exactly one `history::Event::Complete(value)` carrying the commit graph; the local `graph` variable is `Option` and `ok_or_else` converts `None` into this error. It is an invariant check: the traversal callback sets `graph = Some(value)` when the complete event arrives, so absence means the traversal ended without a completion event.
Solutions
- Verify the repository has at least one reachable commit not excluded by hidden refs/pins/worktrees — unhide a tip and retry.
- Check that the traversal callback's `Event::Complete` arm is actually reached (add logging/assertion before `ok_or_else`).
- Trace whether the traversal aborted early and returned an error that was swallowed; propagate it instead.
- Guard the call site: refuse to run the overview when the filtered tip set is empty.
Example fix
// before
let graph = graph.ok_or_else(|| anyhow::anyhow!("history traversal did not produce a graph"))?;
// after
let graph = graph.ok_or_else(|| anyhow::anyhow!(
"history traversal did not produce a graph (no reachable commits after applying hidden refs)"
))?; Defensive patterns
Strategy: validation
Validate before calling
fn traversal_can_produce_graph(repo: &gix::Repository, hidden: &[gix::RefSpec]) -> bool {
repo.head().ok().map(|h| h.is_detached() || h.referent().is_ok()).unwrap_or(false)
&& repo.references().map(|r| r.all().map(|i| i.count() > 0).unwrap_or(false)).unwrap_or(false)
} Type guard
fn has_complete_event(events: &[crate::history::Event]) -> bool {
events.iter().any(|e| matches!(e, crate::history::Event::Complete(_)))
} Try / catch
match build_overview(&repo, ...) {
Err(e) if e.to_string().contains("history traversal did not produce a graph") => {
eprintln!("No reachable commits after hidden refs; unhide a tip or check the repo is non-empty");
}
res => res?,
} Prevention
- Check the repository has at least one commit before opening the overview
- Do not hide every tip via pins/worktree filters
- Assert the traversal emits `Event::Complete` in tests
- Propagate traversal errors instead of letting the producer finish silently
When it happens
Trigger: The traversal producing the overview graph (ref_tree.rs:1515) finished without ever yielding `Event::Complete` — e.g. the traversal aborted early on error, the callback filtered/ignored the event, or the traversal produced zero commits because no reachable tips remained after hiding refs/pins/worktrees.
Common situations: An empty repository or one where every tip is hidden by refs/pins/worktree filters, so nothing is traversed; an early traversal error path that still returns `Ok` upstream; a regression in the history producer no longer emitting the complete event.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- could not decode commit-graph parent
- visit_non_tree() called us
- BUG: ResolvedSignatures don't exist here when nothing is set
- initial hunks are never ancestors
- only value and unspecified are possible here
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/e1bdafd49555929a.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/ref_tree.rs:1515
let authors = gix::features::threading::OwnShared::new(gix::features::threading::Mutable::new(
crate::history::Authors::default(),
));
let mut graph = None;
crate::history::load(
repository,
&visible_revisions,
hidden,
true,
&authors,
&AtomicBool::new(false),
|event| {
if let crate::history::Event::Complete(value) = event {
graph = Some(value);
}
true
},
)?;
let graph = graph.ok_or_else(|| anyhow::anyhow!("history traversal did not produce a graph"))?;
let hidden_refs = hidden_refs.into_keys().collect();
let decorations = crate::history::decorations_excluding(repository, &refs.pins, &refs.worktrees, &hidden_refs)?;
refs.hidden_tips.clear();
let overview = Overview::new(&graph, &refs, &decorations, show_tags);
let labels = overview
.nodes
.iter()
.filter(|node| node.raw_tip && node.decorations.is_empty())
.map(|node| Ok((node.id, crate::change_id::display(repository, node.id, 7)?)))
.collect::<anyhow::Result<HashMap<_, _>>>()?;
Ok(render_overview(&overview, unicode, &labels))
}
fn render_overview(overview: &Overview, unicode: bool, commit_labels: &HashMap<ObjectId, String>) -> String {
if overview.nodes.is_empty() {
return String::new();
}
let placed = place_rail(overview, None);View on GitHub (pinned to e73179060b)