gitbutlerapp/gitbutler · error

BUG: this must have been deactivated

Error message

BUG: this must have been deactivated

What it means

When `create_tree` snapshots the index into the snapshot tree (but-core/src/snapshot/create_tree.rs), `Change::Rewrite` from the tree↔index diff is `unreachable!` because that diff is created with rewrite detection deactivated, so the index diff only emits plain modifications/additions/deletions. The panic indicates the diff producing these changes was built with rename/copy rewrites enabled, breaking the snapshot builder's assumption.

Source

Thrown at crates/but-core/src/snapshot/create_tree.rs:239

                    ..
                }
                | Change::Modification {
                    location,
                    entry_mode,
                    id,
                    ..
                } => {
                    base_tree_edit.upsert(
                        location.as_bstr(),
                        entry_mode
                            .to_tree_entry_mode()
                            .with_context(|| format!("Could not convert the index entry {entry_mode:?} at '{location}' into a tree entry kind"))?
                            .kind(),
                        id.into_owned(),
                    )?;
                }
                Change::Rewrite { .. } => {
                    unreachable!("BUG: this must have been deactivated")
                }
            }
        }

        let index = base_tree_edit.write()?;
        let index = (index != base_tree.id).then_some(index.detach());
        if let Some(index) = index {
            snapshot_tree.upsert("index", EntryKind::Tree, index)?;
        }

        let index_conflicts = if conflicts.is_empty() {
            None
        } else {
            let mut root = snapshot_tree.cursor_at("index-conflicts")?;
            for (rela_path, conflict_entries) in conflicts {
                for (stage, entry) in conflict_entries
                    .into_iter()
                    .enumerate()

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Create the diff for snapshot tree building with rewrite detection `None`.
  2. Keep rename-aware diffs in a separate platform instance consumed only by display code.
  3. Regression-test snapshot creation after any change to shared diff options.

Example fix

// before
let changes = repo.diff_tree_to_index(base_tree, None, gix::diff::tree::Options {
    rewrites: Some(gix::diff::Rewrites::default()),
    ..Default::default()
})?; // Rewrite changes reach create_tree

// after
let changes = repo.diff_tree_to_index(base_tree, None, gix::diff::tree::Options {
    rewrites: None, // snapshot path expects no Rewrite variants
    ..Default::default()
})?;
Defensive patterns

Strategy: validation

Validate before calling

// snapshot tree building requires a rewrite-free tree-to-index diff
let changes = repo.diff_tree_to_index(
    base_tree,
    None,
    gix::diff::tree::Options { rewrites: None, ..Default::default() },
)?;

Prevention

When it happens

Trigger: Constructing the tree↔index diff with `gix::diff::Rewrites` enabled and passing its changes into the snapshot tree builder; option plumbing changes that share a rewrite-enabled platform with snapshot creation; gix version default changes.

Common situations: Reusing one diff platform configured for rename-aware UI across snapshot code; refactors that centralize diff options; dependency upgrades.

Related errors


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