{"record":{"id":"ecaaf62b8b01ddc4","repo":"plandex-ai/plandex","slug":"error-rejecting-result","errorCode":null,"errorMessage":"Error rejecting result: ","messagePattern":"Error rejecting result: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_changes.go","lineNumber":355,"sourceCode":"\t\tCancelFn:       cancel,\n\t\tClearRepoOnErr: true,\n\t}, func(repo *db.GitRepo) error {\n\t\terr = db.RejectPlanFile(auth.OrgId, planId, req.FilePath, time.Now())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = repo.GitAddAndCommit(branch, fmt.Sprintf(\"🚫 Rejected pending changes to file: %s\", req.FilePath))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error committing rejected changes: %v\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tlog.Printf(\"Error rejecting result: %v\\n\", err)\n\t\thttp.Error(w, \"Error rejecting result: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully rejected plan file\", req.FilePath)\n}\n\nfunc RejectFilesHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received request for RejectFilesHandler\")\n\n\tauth := Authenticate(w, r, true)\n\tif auth == nil {\n\t\treturn\n\t}\n\n\tvars := mux.Vars(r)\n\tplanId := vars[\"planId\"]\n\tbranch := vars[\"branch\"]\n","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_changes.go#L337-L373","documentation":"The repository operation inside RejectFileHandler's ExecRepoOperation transaction failed — either db.RejectPlanFile (DB/repo update) or repo.GitAddAndCommit (git commit of the reverted file) returned an error. The handler maps any of these to HTTP 500.","triggerScenarios":"RejectPlanFile fails (plan/file row not found, DB error), or GitAddAndCommit fails (git lock file present, dirty/unmerged index, missing branch, repo corruption) while rejecting a single file's pending changes.","commonSituations":"Concurrent operations holding the repo write lock; leftover .git/index.lock after a crash; branch deleted while request in flight; DB connectivity loss mid-transaction; ClearRepoOnErr wipes the local repo so a retry starts clean.","solutions":["Read the wrapped err.Error() in the 500 response to see whether the DB step or the git commit step failed","If it's a git error, check for stale .git/index.lock in the plan's repo and retry (ClearRepoOnErr already reset it)","Verify the plan/branch still exist and no other operation holds the write lock","Retry the request; if DB errors persist, check database connectivity/logs"],"exampleFix":"// server already resets the repo on failure — client-side recovery\n// before\nawait rejectFile(planId, branch, filePath);\n// after\ntry {\n  await rejectFile(planId, branch, filePath);\n} catch (e) {\n  if (e.status === 500) await retryWithBackoff(() => rejectFile(planId, branch, filePath));\n}","handlingStrategy":"retry","validationCode":"const plan = await getPlan(planId, branch);\nif (!plan.pendingFiles?.includes(filePath)) throw new Error('File has no pending changes to reject');","typeGuard":"function isGitLockError(msg) { return typeof msg === 'string' && msg.includes('index.lock'); }","tryCatchPattern":"try { await rejectFile(planId, branch, filePath); } catch (e) { if (e.status === 500 && !isGitLockError(e.message)) await retryWithBackoff(() => rejectFile(planId, branch, filePath)); else throw e; }","preventionTips":["Avoid concurrent mutations of the same plan/branch","Retry on 500 — the server clears the repo on error so retries start clean","For git lock errors, alert ops instead of hammering retries","Check plan/branch still exist before calling"],"tags":["http","git","database","internal-server-error","go"],"backgroundTag":"git-operation-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}