{"record":{"id":"7c941b3fac63ffd1","repo":"affaan-m/ECC","slug":"selected-hunk-is-already-staged","errorCode":null,"errorMessage":"selected hunk is already staged","messagePattern":"selected hunk is already staged","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"ecc2/src/worktree/mod.rs","lineNumber":404,"sourceCode":"            &unstaged_patch,\n        ));\n    }\n\n    if sections.is_empty() {\n        Ok(None)\n    } else {\n        Ok(Some(GitStatusPatchView {\n            path: entry.path.clone(),\n            display_path: entry.display_path.clone(),\n            patch: sections.join(\"\\n\\n\"),\n            hunks,\n        }))\n    }\n}\n\npub fn stage_hunk(worktree: &WorktreeInfo, hunk: &GitPatchHunk) -> Result<()> {\n    if hunk.section != GitPatchSectionKind::Unstaged {\n        anyhow::bail!(\"selected hunk is already staged\");\n    }\n    git_apply_patch(\n        &worktree.path,\n        &[\"--cached\"],\n        &hunk.patch,\n        \"stage selected hunk\",\n    )\n}\n\npub fn unstage_hunk(worktree: &WorktreeInfo, hunk: &GitPatchHunk) -> Result<()> {\n    if hunk.section != GitPatchSectionKind::Staged {\n        anyhow::bail!(\"selected hunk is not staged\");\n    }\n    git_apply_patch(\n        &worktree.path,\n        &[\"-R\", \"--cached\"],\n        &hunk.patch,\n        \"unstage selected hunk\",","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/worktree/mod.rs#L386-L422","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: uniform handler\nstage_hunk(&worktree, &hunk)?;\n\n// after: guard by section\nif hunk.section == GitPatchSectionKind::Unstaged {\n    stage_hunk(&worktree, &hunk)?;\n}","handlingStrategy":"type-guard","validationCode":"if hunk.section != GitPatchSectionKind::Unstaged {\n    return Err(anyhow!(\"hunk is already staged; nothing to stage\"));\n}","typeGuard":"fn is_stageable(hunk: &GitPatchHunk) -> bool {\n    matches!(hunk.section, GitPatchSectionKind::Unstaged)\n}","tryCatchPattern":"match stage_hunk(&worktree, &hunk) {\n    Ok(()) => refresh_patch_view(),\n    Err(e) if e.to_string().contains(\"already staged\") => refresh_patch_view(),\n    Err(e) => eprintln!(\"stage hunk failed: {e:#}\"),\n}","preventionTips":["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."],"tags":["git","precondition","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}