{"record":{"id":"2027d8de7c57070d","repo":"gitbutlerapp/gitbutler","slug":"failed-to-remove-specified-changes-from-commit","errorCode":null,"errorMessage":"Failed to remove specified changes from commit","messagePattern":"Failed to remove specified changes from commit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/commit/uncommit_changes.rs","lineNumber":220,"sourceCode":"    commit: impl ToCommitSelector,\n    changes: impl IntoIterator<Item = DiffSpec>,\n    context_lines: u32,\n) -> Result<Selector> {\n    let (commit_selector, commit) = editor.find_selectable_commit(commit)?;\n\n    if commit.clone().attach(editor.repo()).is_conflicted() {\n        bail!(\"Cannot uncommit changes from a conflicted commit\")\n    }\n\n    let (tree_without_changes, dropped_diffs) = create_tree_without_diff(\n        editor.repo(),\n        ChangesSource::Commit { id: commit.id },\n        changes,\n        context_lines,\n    )?;\n\n    if !dropped_diffs.is_empty() {\n        bail!(\"Failed to remove specified changes from commit\");\n    }\n\n    let new_commit_id = {\n        let mut new_commit = commit.clone();\n        new_commit.tree = tree_without_changes;\n        editor.new_commit(new_commit, DateMode::CommitterUpdateAuthorKeep)?\n    };\n\n    editor.replace(commit_selector, Step::new_pick(new_commit_id))?;\n    Ok(commit_selector)\n}\n\nfn group_sources_by_commit(\n    sources: impl IntoIterator<Item = UncommitChangesSource>,\n) -> Vec<GroupedUncommitChanges> {\n    let mut groups = Vec::<GroupedUncommitChanges>::new();\n    for source in sources {\n        if let Some(group) = groups","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/commit/uncommit_changes.rs#L202-L238","documentation":"After constructing a tree with the requested diffs removed, the code verifies that every requested diff was actually dropped (dropped_diffs empty). If any requested change could not be found/removed in the commit's tree, the operation is considered failed because the result would silently differ from the request.","triggerScenarios":"Calling uncommit_changes_no_rebase with DiffSpecs that don't match actual content in the commit (wrong paths, stale file hashes, hunks that don't exist in the commit's tree, already-removed changes).","commonSituations":"Stale UI state where the user selected lines from an older version of the commit; passing file paths that were never part of the commit; hunk specs computed against the worktree rather than the commit tree.","solutions":["Refresh the diffs for the commit and pass specs derived from its current tree","Verify each requested change (path and content) actually exists in the target commit before calling","Remove the stale/invalid specs from the request and retry","If the change lives elsewhere (worktree, another commit), uncommit from that source instead"],"exampleFix":"// before\nbut.uncommit_changes_no_rebase(commit, stale_specs); // bails: spec not in commit\n// after\nlet fresh_specs = commit.diff_specs(repo)?;\nlet wanted = fresh_specs.into_iter().filter(|s| user_selected(s));\nbut.uncommit_changes_no_rebase(commit, wanted);","handlingStrategy":"validation","validationCode":"let available = commit.diff_specs(&repo)?;\nlet valid: Vec<_> = requested.into_iter().filter(|s| available.contains(s)).collect();\nassert_eq!(valid.len(), requested_count); // all requested specs must exist","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"Failed to remove specified changes\") => {\n        // refresh specs from the commit tree and retry once\n    }\n    other => other?,\n}","preventionTips":["Always derive DiffSpecs from the commit's current tree, not the worktree","Invalidate cached selections whenever the underlying commit changes","Log and drop stale specs instead of passing them through"],"tags":["git","diff","validation"],"backgroundTag":"invalid-argument-value","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"}