{"record":{"id":"e1bdafd49555929a","repo":"GitoxideLabs/gitoxide","slug":"history-traversal-did-not-produce-a-graph","errorCode":null,"errorMessage":"history traversal did not produce a graph","messagePattern":"history traversal did not produce a graph","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-tix/src/ref_tree.rs","lineNumber":1515,"sourceCode":"    let authors = gix::features::threading::OwnShared::new(gix::features::threading::Mutable::new(\n        crate::history::Authors::default(),\n    ));\n    let mut graph = None;\n    crate::history::load(\n        repository,\n        &visible_revisions,\n        hidden,\n        true,\n        &authors,\n        &AtomicBool::new(false),\n        |event| {\n            if let crate::history::Event::Complete(value) = event {\n                graph = Some(value);\n            }\n            true\n        },\n    )?;\n    let graph = graph.ok_or_else(|| anyhow::anyhow!(\"history traversal did not produce a graph\"))?;\n    let hidden_refs = hidden_refs.into_keys().collect();\n    let decorations = crate::history::decorations_excluding(repository, &refs.pins, &refs.worktrees, &hidden_refs)?;\n    refs.hidden_tips.clear();\n    let overview = Overview::new(&graph, &refs, &decorations, show_tags);\n    let labels = overview\n        .nodes\n        .iter()\n        .filter(|node| node.raw_tip && node.decorations.is_empty())\n        .map(|node| Ok((node.id, crate::change_id::display(repository, node.id, 7)?)))\n        .collect::<anyhow::Result<HashMap<_, _>>>()?;\n    Ok(render_overview(&overview, unicode, &labels))\n}\n\nfn render_overview(overview: &Overview, unicode: bool, commit_labels: &HashMap<ObjectId, String>) -> String {\n    if overview.nodes.is_empty() {\n        return String::new();\n    }\n    let placed = place_rail(overview, None);","sourceCodeStart":1497,"sourceCodeEnd":1533,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-tix/src/ref_tree.rs#L1497-L1533","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet graph = graph.ok_or_else(|| anyhow::anyhow!(\"history traversal did not produce a graph\"))?;\n// after\nlet graph = graph.ok_or_else(|| anyhow::anyhow!(\n    \"history traversal did not produce a graph (no reachable commits after applying hidden refs)\"\n))?;","handlingStrategy":"validation","validationCode":"fn traversal_can_produce_graph(repo: &gix::Repository, hidden: &[gix::RefSpec]) -> bool {\n    repo.head().ok().map(|h| h.is_detached() || h.referent().is_ok()).unwrap_or(false)\n        && repo.references().map(|r| r.all().map(|i| i.count() > 0).unwrap_or(false)).unwrap_or(false)\n}","typeGuard":"fn has_complete_event(events: &[crate::history::Event]) -> bool {\n    events.iter().any(|e| matches!(e, crate::history::Event::Complete(_)))\n}","tryCatchPattern":"match build_overview(&repo, ...) {\n    Err(e) if e.to_string().contains(\"history traversal did not produce a graph\") => {\n        eprintln!(\"No reachable commits after hidden refs; unhide a tip or check the repo is non-empty\");\n    }\n    res => res?,\n}","preventionTips":["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"],"tags":["internal-invariant","commit-graph","traversal","empty-result"],"backgroundTag":"empty-result-set","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"}