{"record":{"id":"8186c9cb01f95ad8","repo":"plandex-ai/plandex","slug":"error-committing-plan-build-v","errorCode":null,"errorMessage":"error committing plan build: %v","messagePattern":"error committing plan build: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/model/plan/build_finish.go","lineNumber":135,"sourceCode":"\t\t\t}(desc)\n\t\t}\n\n\t\tfor range unbuiltDescs {\n\t\t\terr = <-descErrCh\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error storing description: %v\\n\", err)\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\terr = repo.GitAddAndCommit(branch, currentPlan.PendingChangesSummaryForBuild())\n\n\t\tif err != nil {\n\t\t\tif strings.Contains(err.Error(), \"nothing to commit\") {\n\t\t\t\tlog.Println(\"Nothing to commit\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"error committing plan build: %v\", err)\n\t\t}\n\n\t\tlog.Println(\"Plan build committed\")\n\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tlog.Printf(\"Error finishing build: %v\\n\", err)\n\n\t\tif err.Error() != context.Canceled.Error() {\n\t\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"error finishing build: %v\", err))\n\n\t\t\tap.StreamDoneCh <- &shared.ApiError{\n\t\t\t\tType:   shared.ApiErrorTypeOther,\n\t\t\t\tStatus: http.StatusInternalServerError,\n\t\t\t\tMsg:    \"Error finishing build: \" + err.Error(),\n\t\t\t}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/build_finish.go#L117-L153","documentation":"This error is returned from onFinishBuild in plan/build_finish.go when GitAddAndCommit fails while committing the plan's pending changes inside a repo write lock. Plandex stores plan builds as git commits on an internal branch; if the commit command returns anything other than \"nothing to commit\" it is wrapped as \"error committing plan build: %v\" and propagated to the stream as a 500 ApiError. It means the internal git repo operation failed, not that the plan itself is wrong.","triggerScenarios":"Calling onFinishBuild after all file builds complete and repo.GitAddAndCommit returns an error other than \"nothing to commit\": git binary missing or not on PATH, corrupted internal .git directory, git index.lock left over from a killed process, disk full, permission problems on the plans repo directory, or branch ref write failures.","commonSituations":"Self-hosted deployments with a full disk or a plans data volume owned by the wrong user; concurrent processes contending for the same repo leaving a stale index.lock; upgrading/moving the data dir and breaking git object permissions; container images missing the git binary.","solutions":["Check the wrapped inner error in the log (\"Error finishing build: error committing plan build: ...\") to identify the root cause (disk full, permissions, index.lock, etc.)","If a stale git index.lock exists in the plan's internal repo, remove it and retry the build","Verify git is installed and executable by the server process, and that the plans data directory is writable","Check available disk space and filesystem health on the volume holding plan repos","If the internal repo is corrupted, restore from backup or re-initialize the plan's git repo"],"exampleFix":"// before\nerr = repo.GitAddAndCommit(branch, currentPlan.PendingChangesSummaryForBuild())\nif err != nil {\n\treturn fmt.Errorf(\"error committing plan build: %v\", err)\n}\n// after\nerr = repo.GitAddAndCommit(branch, currentPlan.PendingChangesSummaryForBuild())\nif err != nil {\n\tif strings.Contains(err.Error(), \"index.lock\") {\n\t\tos.Remove(filepath.Join(repo.Dir, \".git\", \"index.lock\")) // clear stale lock, then retry\n\t\terr = repo.GitAddAndCommit(branch, currentPlan.PendingChangesSummaryForBuild())\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error committing plan build: %v\", err)\n\t}\n}","handlingStrategy":"retry","validationCode":"// before running a plan build, check repo health\nif _, err := os.Stat(filepath.Join(repoDir, \".git\", \"index.lock\")); err == nil {\n\treturn fmt.Errorf(\"stale git index.lock present in %s; remove it before building\", repoDir)\n}\nout, err := exec.LookPath(\"git\")\nif err != nil {\n\treturn fmt.Errorf(\"git binary not found on PATH\")\n}\nif err := hasFreeDiskSpace(dataDir, 100<<20); err != nil { // need >=100MB\n\treturn err\n}","typeGuard":null,"tryCatchPattern":"if err := db.ExecRepoOperation(...); err != nil {\n\tif strings.Contains(err.Error(), \"index.lock\") {\n\t\t// clear stale lock and retry once\n\t} else if strings.Contains(err.Error(), \"no space left\") {\n\t\t// alert ops: disk full\n\t} else {\n\t\t// surface wrapped \"error committing plan build\" with inner cause\n\t}\n}","preventionTips":["Monitor disk space and permissions on the volume storing plan git repos","Ensure the server container image includes the git binary","Clean up stale index.lock files after server crashes (startup health check)","Avoid running multiple server instances against the same plans data directory"],"tags":["git","filesystem","plandex","server","commit"],"backgroundTag":"git-commit-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"}