{"record":{"id":"6c6c4bfcf4b5453a","repo":"gastownhall/beads","slug":"auto-export-git-add-failed-w","errorCode":null,"errorMessage":"auto-export: git add failed: %w","messagePattern":"auto-export: git add failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/bd/export_auto.go","lineNumber":227,"sourceCode":"\tif issueCount == 0 && memoryCount == 0 {\n\t\t_ = os.Remove(fullPath)\n\t\tsaveExportAutoState(beadsDir, &exportAutoState{\n\t\t\tLastDoltCommit: currentCommit,\n\t\t\tLastDiffAnchor: anchorCommit,\n\t\t\tLastDirtyIDs:   dirtyIDs,\n\t\t\tTimestamp:      time.Now(),\n\t\t\tIssues:         0,\n\t\t\tMemories:       0,\n\t\t})\n\t\treturn nil\n\t}\n\twarnJSONLWithoutDoltRemote(\"auto-export\")\n\n\t// Optional git add — skip when no-git-ops is set (GH#3314), when not in a\n\t// git repo (standalone BEADS_DIR flow), or when export.git-add is false.\n\tif config.GetBool(\"export.git-add\") && !config.GetBool(\"no-git-ops\") && isGitRepo() {\n\t\tif err := gitAddFile(fullPath); err != nil {\n\t\t\treturn fmt.Errorf(\"auto-export: git add failed: %w\", err)\n\t\t}\n\t}\n\n\t// Save state\n\tnewState := exportAutoState{\n\t\tLastDoltCommit: currentCommit,\n\t\tLastDiffAnchor: anchorCommit,\n\t\tLastDirtyIDs:   dirtyIDs,\n\t\tTimestamp:      time.Now(),\n\t\tIssues:         issueCount,\n\t\tMemories:       memoryCount,\n\t}\n\tsaveExportAutoState(beadsDir, &newState)\n\treturn nil\n}\n\n// storeStateHash returns the hash used for auto-export change detection.\n// It prefers a working-set-aware hash (storage.StateHasher) over the HEAD","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/export_auto.go#L209-L245","documentation":"maybeAutoExport optionally stages the exported .beads/issues.jsonl with git when config export.git-add is true, no-git-ops is not set, and the directory is a git repo. If gitAddFile fails (git itself errored), the export state is not saved and this wrapped error is returned so the caller can warn/abort.","triggerScenarios":"gitAddFile fails: git not on PATH, path not actually in a git repo despite isGitRepo race, git index.lock held by another process, or git hook/permission failures on add.","commonSituations":"Concurrent `bd` and IDE git operations contending for .git/index.lock; BEADS_DIR relocated outside the repo mid-run; bare-broken git install; ownership/safe.directory errors in containers.","solutions":["Re-run after the competing git process exits (check for .git/index.lock and remove it only if stale)","Ensure the working directory is a healthy git repo (`git status`) and git is installed","Set `no-git-ops` or export.git-add=false to skip staging; the JSONL export itself still succeeded","Check git's own stderr via the wrapped cause for safe.directory/permission hints"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-checks matching the command's own guards\nif !isGitRepo() || config.GetBool(\"no-git-ops\") || !config.GetBool(\"export.git-add\") { skipGitAdd() }\nif _, err := os.Stat(\".git/index.lock\"); err == nil { deferGitAdd() }","typeGuard":null,"tryCatchPattern":"if err := maybeAutoExport(ctx); err != nil {\n    if strings.Contains(err.Error(), \"git add failed\") {\n        // export already written; stage later or disable export.git-add\n        log.Warn(\"auto-export staged export failed\", \"err\", err)\n    }\n}","preventionTips":["Don't run competing git operations (IDEs, hooks) at the same moment as bd export","Set export.git-add=false or no-git-ops in environments where git is unreliable","Keep git installed and the repo healthy (`git status` clean-run) in CI containers"],"tags":["git","auto-export","cli"],"backgroundTag":"git-add-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}