affaan-m/ECC · warning
selected hunk is not staged
Error message
selected hunk is not staged
What it means
unstage_hunk unstages a hunk by reverse-applying its patch to the index (`git apply -R --cached`) and therefore requires the hunk to come from the staged section. If the hunk's section is Unstaged, the library throws this precondition error because an unstaged hunk cannot be removed from the index.
Solutions
- Verify hunk.section == GitPatchSectionKind::Staged before calling unstage_hunk.
- Re-fetch the patch view after every stage/unstage/reset operation so hunk sections reflect current index state.
- Route unstaged hunks to stage_hunk (or discard via reset_hunk) instead.
Example fix
// before
unstage_hunk(&worktree, &hunk)?;
// after
if hunk.section == GitPatchSectionKind::Staged {
unstage_hunk(&worktree, &hunk)?;
} Defensive patterns
Strategy: type-guard
Validate before calling
if hunk.section != GitPatchSectionKind::Staged {
return Err(anyhow!("hunk is not staged; nothing to unstage"));
} Type guard
fn is_unstageable(hunk: &GitPatchHunk) -> bool {
matches!(hunk.section, GitPatchSectionKind::Staged)
} Try / catch
match unstage_hunk(&worktree, &hunk) {
Ok(()) => refresh_patch_view(),
Err(e) if e.to_string().contains("not staged") => refresh_patch_view(),
Err(e) => eprintln!("unstage hunk failed: {e:#}"),
} Prevention
- Only call unstage_hunk for hunks rendered in the staged diff panel.
- Refresh hunk data after any staging operation; section membership is volatile.
- Use a single dispatcher that routes by hunk.section instead of per-panel handlers.
When it happens
Trigger: Calling unstage_hunk(worktree, hunk) with hunk.section == GitPatchSectionKind::Unstaged, typically from UI code that wires both staged and unstaged diff panels to a single 'unstage' handler.
Common situations: Reusing one context menu for both diff sections; stale hunk objects captured before a previous staging operation moved the hunk between sections.
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 already 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/6d76c81d26dc0ffd.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/worktree/mod.rs:416
}))
}
}
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",
)
}
pub fn reset_hunk(
worktree: &WorktreeInfo,
entry: &GitStatusEntry,
hunk: &GitPatchHunk,
) -> Result<()> {
if entry.untracked {
anyhow::bail!("cannot reset hunks for untracked files");
}
View on GitHub (pinned to 8321021c54)