gitbutlerapp/gitbutler · error

prefiltered

Error message

prefiltered

What it means

Internal invariant panic in but-graph's post-initialization pass. The loop iterates segments collected by prefiltering for a non-empty refs list on the first commit, so the `0 =>` arm of `first_commit.refs.len()` should be unreachable: it only fires if the prefilter and the loop body disagree. This is a bug in but-graph (crates/but-graph/src/init/post.rs), not a caller error.

Source

Thrown at crates/but-graph/src/init/post.rs:556

            .inner
            .node_indices()
            .filter(|sidx| {
                self[*sidx]
                    .commits
                    .first()
                    .is_some_and(|c| !c.refs.is_empty())
            })
            .collect();
        for sidx in segments_with_refs_on_first_commit {
            let s = &mut self.inner[sidx];
            let first_commit = &mut s.commits[0];
            if let Some(srn) = &s.ref_info {
                if let Some(pos) = first_commit.refs.iter().position(|rn| rn == srn) {
                    first_commit.refs.remove(pos);
                }
            } else {
                match first_commit.refs.len() {
                    0 => unreachable!("prefiltered"),
                    1 => {
                        if first_commit
                            .refs
                            .first()
                            .is_some_and(|rn| rn.ref_name.category() == Some(Category::LocalBranch))
                        {
                            s.ref_info = first_commit.refs.pop();
                            s.metadata = meta
                                .branch_opt(s.ref_name().expect("just set"))
                                .ok()
                                .flatten()
                                .map(|md| SegmentMetadata::Branch(md.clone()));
                        }
                    }
                    _ => {
                        if !inserted_proxy_segments.contains(&sidx) {
                            continue;
                        }

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Report a bug to GitButler with the repository/fixture that reproduces it - as an internal unreachable, the graph input is needed to fix the pass ordering
  2. Check for concurrent git processes (another but instance, an IDE, git CLI) mutating refs while the graph initializes, and retry once they are idle
  3. Upgrade but-graph / the but binary to a version containing the fix
  4. As a maintainer: make the filter and loop agree, e.g. re-check emptiness inside the loop (`if s.commits[0].refs.is_empty() { continue; }`) instead of asserting

Example fix

// before (init/post.rs)
let segments_with_refs_on_first_commit: Vec<_> = ...filter(...is_some_and(|c| !c.refs.is_empty()))...collect();
for sidx in segments_with_refs_on_first_commit {
    match first_commit.refs.len() {
        0 => unreachable!("prefiltered"),
        1 => { /* extract ref_info */ }
        _ => {}
    }
}
// after - tolerate the prefilter going stale
for sidx in segments_with_refs_on_first_commit {
    let s = &mut self.inner[sidx];
    if s.commits[0].refs.is_empty() { continue; }
    match s.commits[0].refs.len() { ... }
}
Defensive patterns

Strategy: try-catch

Try / catch

// graph init is an internal-invariant panic; isolate it if it can take down a host app
use std::panic::{catch_unwind, AssertUnwindSafe};
let graph = catch_unwind(AssertUnwindSafe(|| but_graph::init(&repo).build()))
    .map_err(|p| anyhow::anyhow!("but_graph init panicked (likely bug in init/post.rs): {p:?}"))?;

Prevention

When it happens

Trigger: Running but_graph::init over a repository where a segment that passed the `!c.refs.is_empty()` filter ends up with an empty first-commit refs list by the time the loop body runs - e.g. an earlier pass in the same loop emptied the refs, or refs changed between collection and processing. Any `but_graph` init/`Graph` construction path reaches this code.

Common situations: Modifying the init/post.rs passes during development and breaking the prefilter invariant; corrupted or unusual ref layouts (empty ref names, races with a concurrent git process deleting refs while the graph is built); version drift between but-graph passes.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/87806b615dfe9edd. Report an issue: GitHub.