gitbutlerapp/gitbutler · error
Deletions or additions aren't well-defined for hunk-based…
Error message
Deletions or additions aren't well-defined for hunk-based operations - use the whole-file mode instead: '{wt_change.path}' What it means
Thrown by discard_workspace_changes when a worktree change to discard has status Addition or Deletion but the operation is hunk-based (hunks are being selectively discarded). Discarding 'some hunks' of a file that was newly added or entirely deleted is undefined, so the library rejects it and points to whole-file mode. It mirrors error 420 on the discard side.
Solutions
- Route Addition/Deletion changes to a whole-file discard API instead of the hunk-based path.
- Filter the change list before calling: only pass TreeStatus::Modification/Rename entries to hunk discard.
- For a pure Addition, discard the whole file (delete it); for a Deletion, restore the whole file.
Example fix
// before
wt_changes.iter().for_each(|c| discard_workspace_changes(repo, c, hunks));
// after
for c in wt_changes {
if matches!(c.status, TreeStatus::Addition{..} | TreeStatus::Deletion{..}) {
discard_whole_file(repo, c)?; // whole-file mode
} else {
discard_workspace_changes(repo, c, hunks)?;
}
} Defensive patterns
Strategy: validation
Validate before calling
fn is_hunk_discardable(c: &WorktreeChange) -> bool {
!matches!(c.status, TreeStatus::Addition{..} | TreeStatus::Deletion{..})
} Try / catch
// anyhow callers
match discard_workspace_changes(...) {
Err(e) if e.to_string().contains("well-defined for hunk-based") => discard_whole_file(change)?,
other => other?,
} Prevention
- Partition changes into hunk-discardable and whole-file queues before calling the API
- Disable line-level discard affordances for added/deleted files in the UI
- Map statuses to the correct discard mode in one central helper
When it happens
Trigger: Calling discard_workspace_changes (via any of its public entry points such as all_file_types_deleted_in_worktree or replace_dir_with_file_discard_*) with a TreeStatus::Addition or TreeStatus::Deletion change while hunk-level discard is requested.
Common situations: Selective line-discarding in a worktree UI: the user picks lines to discard inside a newly created file or in a file whose deletion is staged in the worktree. Automated flows that pass every worktree change to hunk-based discard without filtering add/delete statuses.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- `but setup` cannot run from a linked worktree; run it from…
- Cannot currently work in repositories without a worktree
- Cannot currently work in repositories without a worktree
- Cannot hash directory entries that aren't files or symlinks
- Cannot restore branch
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/e3fc998b5afb2a67.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-workspace/src/tree_manipulation/discard_worktree_changes.rs:140
&mut index,
previous_path.as_bstr(),
previous_state,
file::RestoreMode::Deleted,
&mut path_check,
&mut initial_entries_len,
)?;
file::purge_and_restore_from_head_tree(
&mut index,
wt_change.path.as_bstr(),
&mut path_check,
initial_entries_len,
)?;
}
}
} else {
match wt_change.status {
TreeStatus::Addition { .. } | TreeStatus::Deletion { .. } => {
bail!(
"Deletions or additions aren't well-defined for hunk-based operations - use the whole-file mode instead: '{}'",
wt_change.path
)
}
TreeStatus::Modification {
previous_state,
flags,
..
}
| TreeStatus::Rename {
previous_state,
flags,
..
} => {
if flags.is_some_and(|f| f.is_typechange()) {
bail!(
"Type-changed items can't be discard by hunks - use the whole-file mode instead"
)View on GitHub (pinned to 58e5313667)