{"record":{"id":"d986d3b90e5f14d1","repo":"plandex-ai/plandex","slug":"error-adding-files-to-git-repository-for-dir-s-d986d3","errorCode":null,"errorMessage":"error adding files to git repository for dir: %s, err: %v","messagePattern":"error adding files to git repository for dir: (.+?), err: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/diff_helpers.go","lineNumber":91,"sourceCode":"\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\terrCh <- nil\n\t\t}(path, context)\n\t}\n\n\tfor range planState.ContextsByPath {\n\t\terr = <-errCh\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error writing original files to temp dir: %v\", err)\n\t\t}\n\t}\n\n\tif hasAnyOriginal {\n\t\t// add and commit the files in the temp dir\n\t\terr := gitAdd(tempDirPath, \".\")\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error adding files to git repository for dir: %s, err: %v\", tempDirPath, err)\n\t\t}\n\n\t\terr = gitCommit(tempDirPath, \"original files\")\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error committing files to git repository for dir: %s, err: %v\", tempDirPath, err)\n\t\t}\n\t}\n\n\t// write the current files to the temp dir\n\terrCh = make(chan error, len(files))\n\n\tfor path, file := range files {\n\t\tgo func(path, file string) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tlog.Printf(\"panic in GetPlanDiffs: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\terrCh <- fmt.Errorf(\"panic in GetPlanDiffs: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\truntime.Goexit() // don't allow outer function to continue and double-send to channel","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/diff_helpers.go#L73-L109","documentation":"After writing original files, GetPlanDiffs stages them with gitAdd(tempDirPath, \".\"). If the `git add` exec fails (non-zero exit), the error is wrapped with the temp dir path for context. Without this commit, the subsequent diff between 'original files' and current files cannot be produced.","triggerScenarios":"gitAdd runs `git add .` in the temp repo and it fails: not a git repo (init failed silently), git missing/broken, index.lock present, or a file violates git rules (e.g. path considered unsafe, too-large file, CRLF/ownership 'dubious ownership' safety error).","commonSituations":"'dubious ownership' errors when the repo dir is owned by another user (common in containers); stale index.lock from a killed process; git not installed; plan file paths flagged by git's safe.directory/protect checks.","solutions":["Run `git -C <tempDir> add .` manually to reproduce and read git's stderr.","If 'dubious ownership' appears, run as the repo owner or set safe.directory appropriately for the service user.","Remove any stale .git/index.lock in the affected directory after confirming no git process is running.","Verify git is installed and on PATH for the server process user."],"exampleFix":"// before\nerr := gitAdd(tempDirPath, \".\")\n// after (retry-safe: clear stale lock first)\nos.Remove(filepath.Join(tempDirPath, \".git\", \"index.lock\"))\nerr := gitAdd(tempDirPath, \".\")","handlingStrategy":"retry","validationCode":"// pre-check repo is functional before add\nif out, err := exec.Command(\"git\", \"-C\", tempDirPath, \"status\", \"--porcelain\").CombinedOutput(); err != nil {\n    return fmt.Errorf(\"temp repo unusable: %v, output: %s\", err, out)\n}","typeGuard":null,"tryCatchPattern":"out, err := GetPlanDiffs(orgId, planId, plain)\nif err != nil && strings.Contains(err.Error(), \"error adding files to git repository\") {\n    lock := filepath.Join(tempDirPath, \".git\", \"index.lock\")\n    if _, statErr := os.Stat(lock); statErr == nil {\n        os.Remove(lock) // stale lock from a killed process\n        // retry the operation\n    }\n}","preventionTips":["Ensure the service user owns temp repos to avoid 'dubious ownership' (safe.directory) failures.","Clear stale index.lock files only after confirming no git process is alive.","Keep git installed and healthy in deployment images.","Avoid unusual filenames that trip git's path safety checks."],"tags":["git","exec","index-lock"],"backgroundTag":"git-add-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}