gitbutlerapp/gitbutler · error
we never return these as the status iteration is configured
Error message
we never return these as the status iteration is configured accordingly
What it means
While assembling worktree tree changes, but-core's status walker matches `index_worktree::Item::DirectoryContents` entries and marks `Status::Tracked | Status::Pruned | Status::Ignored(_)` as `unreachable!` because the gix status iteration is explicitly configured to never emit those (untracked collection with matching traversal and ignored-entry suppression). Hitting it means the iteration configuration used to build the item stream no longer matches what this match assumes — typically after a gix upgrade or an options change.
Source
Thrown at crates/but-core/src/diff/worktree.rs:487
status::Item::IndexWorktree(
index_worktree::Item::Modification {
status: EntryStatus::NeedsUpdate(_),
..
}
| index_worktree::Item::DirectoryContents {
entry:
gix::dir::Entry {
status:
gix::dir::entry::Status::Tracked
| gix::dir::entry::Status::Pruned
| gix::dir::entry::Status::Ignored(_),
..
},
..
},
) => {
unreachable!(
"we never return these as the status iteration is configured accordingly"
)
}
};
tmp.push(change);
}
tmp.sort_by(|(a_origin, a), (b_origin, b)| {
cmp_prefer_overlapping(a, b).then(a_origin.cmp(b_origin).reverse())
});
let mut last_change = None::<&TreeChange>;
let mut changes = Vec::<TreeChange>::with_capacity(tmp.len());
let (mut filter, index) = repo.filter_pipeline(None)?;
let mut path_check = gix::status::plumbing::SymlinkCheck::new(
repo.workdir().map(ToOwned::to_owned).context("non-bare")?,
);
for (_origin, change) in tmp {View on GitHub (pinned to caf1f223d3)
Solutions
- Revert or pin the gix version whose status emission matches the walker's expectations.
- Re-check the status configuration feeding this loop (untracked matching mode, ignore/prune emission flags) and restore the original settings.
- If the new behavior is desired, handle those entries explicitly (skip tracked/pruned/ignored) instead of `unreachable!`, with a regression test.
Example fix
// before
) => {
unreachable!("we never return these as the status iteration is configured accordingly")
}
// after
) => {
// defensive: these are filtered by the configured iteration; skip if ever emitted
continue; // or push nothing for this entry
} Defensive patterns
Strategy: type-guard
Type guard
// skip entries the configured iteration promises never to emit
fn emitted_by_config(status: &gix::dir::entry::Status) -> bool {
!matches!(
status,
gix::dir::entry::Status::Tracked
| gix::dir::entry::Status::Pruned
| gix::dir::entry::Status::Ignored(_)
)
} Prevention
- After any gix bump, run the worktree-diff snapshot tests before merging.
- Keep status options (untracked matching mode, ignore emission) pinned in one constructor so walkers and consumers agree.
- When experimenting with traversal options, do it on a branch with the diff tests enabled.
When it happens
Trigger: Upgrading gix so directory-content emission includes tracked/pruned/ignored entries under some option combinations; changing untracked-files mode or ignore handling in the status options passed into this walker; enabling directory collapse in traversal.
Common situations: Dependency bumps of gix in the GitButler workspace; local experiments toggling `gix::status` options; platforms where traversal defaults differ.
Related errors
- BUG: we use 'matching' so there are no directories
- disabled
- BUG: this must have been deactivated
- BUG: `gix` disables this, as it knows we always need to be a
- worktree-changes are always set if there are hunks
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/87800c2ef8804ebb.
Report an issue: GitHub.