affaan-m/ECC · warning · anyhow::Error
selected hunk is already staged
Error message
selected hunk is already staged
What it means
stage_hunk rejects any hunk whose `section` field is not `GitPatchSectionKind::Unstaged`. This is a precondition guard, not a git failure: the caller handed the function a hunk that lives in the Staged section of the patch view. Staging an already-staged hunk is a no-op the library refuses to perform silently.
Source
Thrown at ecc2/src/worktree/mod.rs:404
&unstaged_patch,
));
}
if sections.is_empty() {
Ok(None)
} else {
Ok(Some(GitStatusPatchView {
path: entry.path.clone(),
display_path: entry.display_path.clone(),
patch: sections.join("\n\n"),
hunks,
}))
}
}
pub fn stage_hunk(worktree: &WorktreeInfo, hunk: &GitPatchHunk) -> Result<()> {
if hunk.section != GitPatchSectionKind::Unstaged {
anyhow::bail!("selected hunk is already staged");
}
git_apply_patch(
&worktree.path,
&["--cached"],
&hunk.patch,
"stage selected hunk",
)
}
pub fn unstage_hunk(worktree: &WorktreeInfo, hunk: &GitPatchHunk) -> Result<()> {
if hunk.section != GitPatchSectionKind::Staged {
anyhow::bail!("selected hunk is not staged");
}
git_apply_patch(
&worktree.path,
&["-R", "--cached"],
&hunk.patch,
"unstage selected hunk",View on GitHub (pinned to 01e15490f0)
Solutions
- Before calling stage_hunk, branch on `hunk.section == GitPatchSectionKind::Unstaged`; for Staged hunks either no-op or route to unstage_hunk.
- Refresh `git_status_patch_view` immediately before acting so hunk.section reflects current state.
- Disable the 'stage' UI affordance when the selected hunk is in the Staged section.
Example fix
// before
stage_hunk(&worktree, &hunk)?;
// after
match hunk.section {
GitPatchSectionKind::Unstaged => stage_hunk(&worktree, &hunk)?,
GitPatchSectionKind::Staged => { /* already staged; no-op */ }
} Defensive patterns
Strategy: validation
Validate before calling
use crate::worktree::{GitPatchHunk, GitPatchSectionKind, stage_hunk};
fn try_stage_hunk(worktree: &WorktreeInfo, hunk: &GitPatchHunk) -> anyhow::Result<()> {
if hunk.section != GitPatchSectionKind::Unstaged {
return Ok(()); // already staged — nothing to do
}
stage_hunk(worktree, hunk)
} Type guard
fn is_unstaged(hunk: &GitPatchHunk) -> bool {
matches!(hunk.section, GitPatchSectionKind::Unstaged)
} Try / catch
match stage_hunk(&worktree, &hunk) {
Ok(()) => { /* refresh */ }
Err(e) if format!("{e}").contains("already staged") => { /* benign no-op */ }
Err(e) => return Err(e),
} Prevention
- Always branch on `hunk.section` before choosing stage vs unstage.
- Refresh `git_status_patch_view` right before acting so section flags are current.
- Disable the stage verb when the selected hunk is in the Staged section.
When it happens
Trigger: Passing a `GitPatchHunk` obtained from the `--- Staged diff ---` section of `git_status_patch_view` into `stage_hunk`. UI dispatches the stage action on the wrong section because it did not check `hunk.section` before choosing the verb.
Common situations: TUI list selection drift where the cursor is on a staged hunk but the stage action is still enabled; copy-paste of hunk references across sections; stale hunk object retained after a status refresh moved it to Staged.
Related errors
- selected hunk is not staged
- cannot reset hunks for untracked files
- cannot reset a staged hunk while the file also has unstaged
- commit message cannot be empty
- no staged changes to commit
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/7c941b3fac63ffd1.
Report an issue: GitHub.