affaan-m/ECC · warning
selected hunk is already staged
Error message
selected hunk is already staged
What it means
stage_hunk only stages hunks that live in the unstaged section of a diff view. If the caller passes a hunk whose section is Staged, the library refuses with this error because there is nothing to stage — the change is already in the index. It is a state precondition check, not a git failure.
Solutions
- Check hunk.section == GitPatchSectionKind::Unstaged before calling stage_hunk; disable the action otherwise.
- Refresh the patch view and use fresh hunk data, since section membership can change after any staging operation.
- Route staged hunks to unstage_hunk (or no-op) in the UI layer instead.
Example fix
// before: uniform handler
stage_hunk(&worktree, &hunk)?;
// after: guard by section
if hunk.section == GitPatchSectionKind::Unstaged {
stage_hunk(&worktree, &hunk)?;
} Defensive patterns
Strategy: type-guard
Validate before calling
if hunk.section != GitPatchSectionKind::Unstaged {
return Err(anyhow!("hunk is already staged; nothing to stage"));
} Type guard
fn is_stageable(hunk: &GitPatchHunk) -> bool {
matches!(hunk.section, GitPatchSectionKind::Unstaged)
} Try / catch
match stage_hunk(&worktree, &hunk) {
Ok(()) => refresh_patch_view(),
Err(e) if e.to_string().contains("already staged") => refresh_patch_view(),
Err(e) => eprintln!("stage hunk failed: {e:#}"),
} Prevention
- Check hunk.section before wiring stage actions in UI handlers.
- Rebuild the patch view after every index mutation; hunks migrate between sections.
- Never reuse hunk objects captured before a previous stage/unstage call.
When it happens
Trigger: Calling stage_hunk(worktree, hunk) with a hunk obtained from the staged side of a patch view (hunk.section == GitPatchSectionKind::Staged), e.g. wiring a UI button to stage for both diff panels without checking section kind.
Common situations: Rendering one unified list of hunks and reusing the stage action for every row; stale UI state where the hunk was staged between render and click; copying a hunk from a staged-diff context into a stage call.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- selected hunk is not staged
- Base branch is not checked out in repo root (currently )
- cannot reset a staged hunk while the file also has unstaged…
- no staged changes to commit
- Repository root has uncommitted changes; commit or stash…
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/7c941b3fac63ffd1.
Report an issue: GitHub.
Appendix: 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 8321021c54)