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
- 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
- Check for concurrent git processes (another but instance, an IDE, git CLI) mutating refs while the graph initializes, and retry once they are idle
- Upgrade but-graph / the but binary to a version containing the fix
- 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
- Run but_graph::init when no other process is mutating refs (close IDEs/git CLI during graph builds)
- Pin the but-graph version that matches your fixture tests so new passes do not surprise you
- When developing passes in init/post.rs, keep the prefilter and the loop-body match arm in one review unit
- Capture the repo state (git bundle / fixture) immediately when the panic fires so it can be reported reproducibly
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
- BUG: {id} is queued
- swap connections of nodes as well
- anchor is always present in the order at this point
- statically known
- symbols must always be initialized
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/87806b615dfe9edd.
Report an issue: GitHub.