{"record":{"id":"82cfbb7525b27140","repo":"plandex-ai/plandex","slug":"error-getting-plan-diffs","errorCode":null,"errorMessage":"Error getting plan diffs: ","messagePattern":"Error getting plan diffs: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_changes.go","lineNumber":570,"sourceCode":"\t\tUserId:   auth.User.Id,\n\t\tPlanId:   planId,\n\t\tBranch:   branch,\n\t\tScope:    db.LockScopeRead,\n\t\tCtx:      ctx,\n\t\tCancelFn: cancel,\n\t}, func(repo *db.GitRepo) error {\n\t\tvar err error\n\t\tdiffs, err = db.GetPlanDiffs(auth.OrgId, planId, plain)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting plan diffs: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting plan diffs: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Printf(\"diffs: %s\", diffs)\n\n\tw.Write([]byte(diffs))\n\n\tlog.Println(\"Successfully retrieved plan diffs\")\n}\n","sourceCodeStart":552,"sourceCodeEnd":580,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_changes.go#L552-L580","documentation":"GetPlanDiffsHandler wraps db.GetPlanDiffs inside db.ExecRepoOperation, which acquires a repo lock and opens the plan's git repo. Any error returned by the lock/repo operation or by GetPlanDiffs itself (SQL failures, git repo errors) surfaces as HTTP 500 'Error getting plan diffs: <err>'.","triggerScenarios":"ExecRepoOperation fails (repo lock contention/cancellation, missing or corrupt plan git repo on disk) or the GetPlanDiffs SQL query errors for orgId/planId.","commonSituations":"Plan's internal git repository missing or corrupted on the server volume; concurrent write lock held on the plan causing wait/cancel (client disconnect cancels ctx); database connectivity failure mid-request; context canceled because the HTTP client timed out.","solutions":["Read the wrapped err.Error() in the server log to distinguish git-repo vs SQL failure","Retry the request — lock contention and transient DB errors are often temporary","Check the plan's repo directory exists and is a valid git repo on the server; restore from backup if corrupted","Verify database connectivity and that the plans/context tables are intact","Keep the client connected (raise timeout) so ctx isn't canceled while waiting for the lock"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-check plan repo exists before calling\nif _, err := os.Stat(repoPath); os.IsNotExist(err) { return fmt.Errorf(\"plan repo missing\") }","typeGuard":null,"tryCatchPattern":"err := db.ExecRepoOperation(params, fn)\nif err != nil {\n\tif errors.Is(err, context.Canceled) { http.Error(w, \"request canceled\", http.StatusRequestTimeout); return }\n\thttp.Error(w, \"Error getting plan diffs: \"+err.Error(), http.StatusInternalServerError)\n}","preventionTips":["Retry on lock-contention errors with backoff","Monitor plan git repo directories for corruption/loss","Keep HTTP client timeouts long enough to survive lock waits","Verify DB connectivity before diagnosing deeper"],"tags":["go","git","database","http-500"],"backgroundTag":"repo-operation-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"}