{"record":{"id":"459f05af57bac379","repo":"gitbutlerapp/gitbutler","slug":"type-changed-items-can-t-be-discard-by-hunks-use","errorCode":null,"errorMessage":"Type-changed items can't be discard by hunks - use the whole-file mode instead","messagePattern":"Type-changed items can't be discard by hunks - use the whole-file mode instead","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/tree_manipulation/discard_worktree_changes.rs","lineNumber":156,"sourceCode":"            match wt_change.status {\n                TreeStatus::Addition { .. } | TreeStatus::Deletion { .. } => {\n                    bail!(\n                        \"Deletions or additions aren't well-defined for hunk-based operations - use the whole-file mode instead: '{}'\",\n                        wt_change.path\n                    )\n                }\n                TreeStatus::Modification {\n                    previous_state,\n                    flags,\n                    ..\n                }\n                | TreeStatus::Rename {\n                    previous_state,\n                    flags,\n                    ..\n                } => {\n                    if flags.is_some_and(|f| f.is_typechange()) {\n                        bail!(\n                            \"Type-changed items can't be discard by hunks - use the whole-file mode instead\"\n                        )\n                    }\n                    hunk::restore_state_to_worktree(\n                        wt_change,\n                        previous_state,\n                        &mut spec.hunk_headers,\n                        &mut path_check,\n                        &mut pipeline,\n                        &index,\n                        context_lines,\n                    )?;\n                    if !spec.hunk_headers.is_empty() {\n                        dropped.push(spec);\n                        continue;\n                    }\n                }\n            }","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/tree_manipulation/discard_worktree_changes.rs#L138-L174","documentation":"Thrown by discard_workspace_changes when a modification/rename change is flagged as a typechange (e.g. file became a symlink or executable transition) and the caller attempts hunk-level discard. Hunk diffs are not meaningful across type changes, so only whole-file mode is allowed. Note the message contains a typo ('can't be discard') but is unconditional for any is_typechange() flag.","triggerScenarios":"Calling discard_workspace_changes with a change whose flags include is_typechange() while requesting hunk-scoped restoration; typically a path whose git entry kind changed between Blob, BlobExecutable, Link, etc.","commonSituations":"A user chmod +x'd a file, or replaced a regular file with a symlink (common on macOS/Linux), then tries to discard selected lines instead of the whole change. Tools that sync permission/symlink changes from other systems.","solutions":["Discard the entire change for typechanged paths rather than selected hunks.","Check change flags for is_typechange() before entering the hunk path and split such changes into a whole-file discard queue.","If only the mode bit changed, restore the whole entry to its previous state with whole-file mode."],"exampleFix":"// before\nhunk::restore_state_to_worktree(wt_change, previous_state, hunks)?;\n\n// after\nif wt_change.flags.is_some_and(|f| f.is_typechange()) {\n    whole_file_restore(wt_change, previous_state)?;\n} else {\n    hunk::restore_state_to_worktree(wt_change, previous_state, hunks)?;\n}","handlingStrategy":"validation","validationCode":"fn is_typechange(c: &WorktreeChange) -> bool {\n    c.flags.is_some_and(|f| f.is_typechange())\n}","typeGuard":null,"tryCatchPattern":"// fall back to whole-file on this specific bail\nif let Err(e) = discard_workspace_changes(...) {\n    if e.to_string().contains(\"Type-changed\") { whole_file_discard(change)?; } else { return Err(e); }\n}","preventionTips":["Check is_typechange() flags before entering any hunk-based code path","Surface chmod/symlink changes as whole-file changes in the UI","Test discard flows against repos containing symlinks and executable-bit changes"],"tags":["git","worktree","typechange"],"backgroundTag":"unsupported-operation","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}