{"record":{"id":"b3c9284056473398","repo":"affaan-m/ECC","slug":"git-commit-failed-stderr","errorCode":null,"errorMessage":"git commit failed: {stderr}","messagePattern":"git commit failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/worktree/mod.rs","lineNumber":472,"sourceCode":"\npub fn commit_staged(worktree: &WorktreeInfo, message: &str) -> Result<String> {\n    let message = message.trim();\n    if message.is_empty() {\n        anyhow::bail!(\"commit message cannot be empty\");\n    }\n    if !has_staged_changes(worktree)? {\n        anyhow::bail!(\"no staged changes to commit\");\n    }\n\n    let output = Command::new(\"git\")\n        .arg(\"-C\")\n        .arg(&worktree.path)\n        .args([\"commit\", \"-m\", message])\n        .output()\n        .context(\"Failed to create commit\")?;\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        anyhow::bail!(\"git commit failed: {stderr}\");\n    }\n\n    let rev_parse = Command::new(\"git\")\n        .arg(\"-C\")\n        .arg(&worktree.path)\n        .args([\"rev-parse\", \"--short\", \"HEAD\"])\n        .output()\n        .context(\"Failed to resolve commit hash\")?;\n    if !rev_parse.status.success() {\n        let stderr = String::from_utf8_lossy(&rev_parse.stderr);\n        anyhow::bail!(\"git rev-parse failed: {stderr}\");\n    }\n\n    Ok(String::from_utf8_lossy(&rev_parse.stdout)\n        .trim()\n        .to_string())\n}\n","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/worktree/mod.rs#L454-L490","documentation":"commit_staged runs `git commit -m <message>` after the pre-flight checks pass. A non-zero exit re-throws git's stderr. The message has already passed the empty-check and staged-changes check, so failure here is typically a hook, signing, or identity problem.","triggerScenarios":"A pre-commit or commit-msg hook exits non-zero; GPG signing requested but no usable key/gpg-agent; `user.email`/`user.name` not configured and git refuses to synthesize an identity; `.git/index.lock` contention; a concurrent commit consumed the staged changes between the check and the commit.","commonSituations":"husky/lefthook running lint+test that fails; CI environment with no `git config --global user.email`; GPG card unplugged; two sessions committing the same worktree simultaneously.","solutions":["Read the stderr in the bail message — it usually names the exact hook or signing failure; fix that root cause first.","Ensure `user.name` and `user.email` are set for the environment (`git config user.email`).","If a pre-commit hook is expected to fail, surface its output to the user instead of opaque retry.","Re-run `has_staged_changes` immediately before commit to close the race window."],"exampleFix":"// before\nlet hash = commit_staged(&worktree, msg)?;\n\n// after\nmatch commit_staged(&worktree, msg) {\n    Ok(hash) => Ok(hash),\n    Err(e) => Err(e).with_context(|| \"commit rejected by git (hook/signing/identity); see stderr above\"),\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight: identity must be configured or git refuses to commit.\nfn git_identity_ok(worktree: &WorktreeInfo) -> bool {\n    let out = std::process::Command::new(\"git\")\n        .arg(\"-C\").arg(&worktree.path)\n        .args([\"config\", \"user.email\"])\n        .output();\n    matches!(out, Ok(o) if o.status.success() && !o.stdout.is_empty())\n}\n\nif !git_identity_ok(&worktree) {\n    anyhow::bail!(\"set git user.email and user.name before committing\");\n}\nlet hash = commit_staged(&worktree, msg)?;","typeGuard":null,"tryCatchPattern":"match commit_staged(&worktree, msg) {\n    Ok(hash) => Ok(hash),\n    Err(e) => {\n        let m = format!(\"{e:#}\");\n        if m.contains(\"hook\") || m.contains(\"pre-commit\") {\n            // surface hook output verbatim; do not retry\n        } else if m.contains(\"user.email\") || m.contains(\"user.name\") {\n            // prompt to configure identity\n        } else if m.contains(\"index.lock\") {\n            // clear lock and retry once\n        }\n        Err(e)\n    }\n}","preventionTips":["Always set `user.name` and `user.email` (global or repo-local) before the first commit.","Treat pre-commit hook failures as user-visible errors and show the hook output.","Hold a single in-flight commit per worktree to avoid index.lock contention.","If signing commits, ensure gpg/ssh signing is configured and the agent is unlocked."],"tags":["git","subprocess","worktree","commit","hooks"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}