{"record":{"id":"0bfcbe6173645bc6","repo":"gastownhall/beads","slug":"w-s","errorCode":null,"errorMessage":"%w: %s","messagePattern":"%w: %s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/export_auto.go","lineNumber":879,"sourceCode":"\t// .beads/issues.jsonl → pathspec looks under .beads/.beads/) if a caller\n\t// ever passed a relative path here. Both current callers pass absolute\n\t// paths, so this guards against a regression rather than fixing a live\n\t// failure. See GH#4351.\n\t// Keep cmd.Dir = parent so GH#3311 hook worktree staging still resolves\n\t// the index path under the repo root (not bare \"issues.jsonl\" at root).\n\tcmd := exec.CommandContext(ctx, \"git\", \"add\", \"--\", filepath.Base(path))\n\tcmd.Dir = filepath.Dir(path)\n\tcmd.Env = env\n\t// Capture combined output so the caller's warning surfaces git's stderr\n\t// (e.g. \"paths are ignored\", \"Unable to create index.lock\") instead of\n\t// just the exit-status text.\n\tout, err := cmd.CombinedOutput()\n\tif ctx.Err() == context.DeadlineExceeded {\n\t\treturn fmt.Errorf(\"git add timed out after %s\", gitAddTimeout)\n\t}\n\tif err != nil {\n\t\tif trimmed := strings.TrimSpace(string(out)); trimmed != \"\" {\n\t\t\treturn fmt.Errorf(\"%w: %s\", err, trimmed)\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc gitIndexLockPath(path string, env []string) (string, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), gitAddTimeout)\n\tdefer cancel()\n\tcmd := exec.CommandContext(ctx, \"git\", \"rev-parse\", \"--git-dir\")\n\tcmd.Dir = filepath.Dir(path)\n\tcmd.Env = env\n\tout, err := cmd.CombinedOutput()\n\tif ctx.Err() == context.DeadlineExceeded {\n\t\treturn \"\", fmt.Errorf(\"git rev-parse timed out after %s\", gitAddTimeout)\n\t}\n\tif err != nil {\n\t\tif trimmed := strings.TrimSpace(string(out)); trimmed != \"\" {","sourceCodeStart":861,"sourceCodeEnd":897,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/export_auto.go#L861-L897","documentation":"When `git add` exits non-zero, gitAddFile wraps the exec error with git's combined stdout/stderr output so the caller's warning shows the real reason (e.g. \"paths are ignored\", \"Unable to create index.lock\") instead of just an exit-status message. The %w preserves the original *exec.ExitError for errors.Is/As checks.","triggerScenarios":"gitAddFile's cmd.CombinedOutput() returns err != nil (non-zero exit from git add) with non-empty output; the exit error is wrapped as \"%w: %s\" with trimmed output appended.","commonSituations":"The JSONL path is gitignored so `git add` refuses; index.lock contention producing \"Unable to create index.lock\"; bad path (file deleted between export and staging); git version/config issues in hooks.","solutions":["Read the appended git output in the error to see the exact git failure and address it","If the path is ignored, adjust .gitignore so .beads/issues.jsonl is tracked (or use explicit `git add -f` policy)","Remove a stale .git/index.lock if output says Unable to create index.lock","If the file is missing, rerun `bd sync`/export to regenerate it"],"exampleFix":"// before\n// exit status 1: The following paths are ignored by one of your .gitignore files: .beads/issues.jsonl\n// after\n# .gitignore\n!.beads/issues.jsonl\nbd sync","handlingStrategy":"try-catch","validationCode":"// Ensure the export path is not gitignored before relying on auto-stage\nout, err := exec.Command(\"git\", \"check-ignore\", \".beads/issues.jsonl\").Output()\nif err == nil && len(out) > 0 {\n    fmt.Println(\"warning: issues.jsonl is gitignored; git add will fail\")\n}","typeGuard":"func isExitErrorWithOutput(err error) (*exec.ExitError, bool) {\n    var ee *exec.ExitError\n    return ee, errors.As(err, &ee)\n}","tryCatchPattern":"var ee *exec.ExitError\nif err := autoExport(); err != nil {\n    if errors.As(err, &ee) && strings.Contains(err.Error(), \"ignored\") {\n        // Fix .gitignore so .beads/issues.jsonl is tracked, then retry\n    } else if errors.As(err, &ee) && strings.Contains(err.Error(), \"index.lock\") {\n        removeStaleLockAndRetry()\n    }\n}","preventionTips":["Keep !.beads/issues.jsonl exceptions in .gitignore templates","Read the git stderr appended to the error before guessing at fixes","Unwrap with errors.As(*exec.ExitError) to branch on git failures programmatically","Validate hook environments don't break git paths"],"tags":["git","exit-error","auto-export"],"backgroundTag":"git-add-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}