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

  1. Route Addition/Deletion changes to a whole-file discard API instead of the hunk-based path.
  2. Filter the change list before calling: only pass TreeStatus::Modification/Rename entries to hunk discard.
  3. 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

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


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)