gitbutlerapp/gitbutler · info
key was just inserted
Error message
key was just inserted
What it means
Panic from `expect("key was just inserted")` in `merge_specs_by_path` (but-workspace uncommit_changes.rs:296). The function maintains two structures in lockstep: `order` records each first-seen `(previous_path, path)` key and `by_path` inserts that same key. The final pass removes each recorded key from the map, so every removal must hit; the expect asserts the map-side of that pairing. Unreachable unless the two structures are desynchronized by an edit.
Source
Thrown at crates/but-workspace/src/commit/uncommit_changes.rs:296
}
Entry::Occupied(mut entry) => {
let existing = entry.get_mut();
if existing.hunk_headers.is_empty() || spec.hunk_headers.is_empty() {
// Whole-file removal supersedes any hunk selection.
existing.hunk_headers.clear();
} else {
for header in spec.hunk_headers {
if !existing.hunk_headers.contains(&header) {
existing.hunk_headers.push(header);
}
}
}
}
}
}
order
.into_iter()
.map(|key| by_path.remove(&key).expect("key was just inserted"))
.collect()
}
fn failure(group: &GroupedUncommitChanges, error: impl Into<String>) -> UncommitChangesFailure {
UncommitChangesFailure {
commit_id: group.commit_id,
changes: group.changes.clone(),
error: error.into(),
}
}
View on GitHub (pinned to caf1f223d3)
Solutions
- No caller-side action — keys are inserted and recorded in the same match arm
- If editing, consider a single structure (e.g. `IndexMap`) so order and storage cannot diverge
- Add a unit test with duplicate paths mixing whole-file and per-hunk specs
Example fix
// before (two structures kept in sync manually)
let mut order = Vec::new();
let mut by_path = HashMap::new();
...
order.into_iter().map(|key| by_path.remove(&key).expect("key was just inserted")).collect()
// after: one structure, no sync to break
use indexmap::IndexMap;
let mut by_path = IndexMap::new();
// merge into by_path.entry(key) ...
by_path.into_iter().map(|(_, spec)| spec).collect::<Vec<_>>() Defensive patterns
Strategy: validation
Prevention
- No input can trigger this in shipped code; order and map are updated in the same match arm
- Maintainers: consider IndexMap to eliminate the two-structure sync, and test duplicate-path spec merging
When it happens
Trigger: Uncommitting selected changes where multiple DiffSpecs target the same file (per-hunk selections), which routes through this merge function; the panic requires a code change that pushes to `order` without inserting into `by_path` (or with a different key), not any input to the shipped code.
Common situations: Maintainers adding rename-aware merging or path normalization between the push and the insert; forks altering the key type; none for end users.
Related errors
- anchor is always present in the order at this point
- validated pick arity above
- validated merge arity above
- checked all selectors are present
- validated non-empty squash commit list
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/31f57a6c7d81a9a7.
Report an issue: GitHub.