{"record":{"id":"1b9d9512155f63e8","repo":"plandex-ai/plandex","slug":"error-deleting-plans","errorCode":null,"errorMessage":"Error deleting plans: ","messagePattern":"Error deleting plans: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/plans_crud.go","lineNumber":286,"sourceCode":"\tauth := Authenticate(w, r, true)\n\tif auth == nil {\n\t\treturn\n\t}\n\n\tvars := mux.Vars(r)\n\tprojectId := vars[\"projectId\"]\n\n\tlog.Println(\"projectId: \", projectId)\n\n\tif !authorizeProject(w, projectId, auth) {\n\t\treturn\n\t}\n\n\terr := db.DeleteOwnerPlans(auth.OrgId, projectId, auth.User.Id)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error deleting plans: %v\\n\", err)\n\t\thttp.Error(w, \"Error deleting plans: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully deleted all plans\")\n}\n\nfunc ListPlansHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received request for ListPlans\")\n\n\tauth := Authenticate(w, r, true)\n\tif auth == nil {\n\t\treturn\n\t}\n\n\tprojectIds := r.URL.Query()[\"projectId\"]\n\n\tlog.Println(\"projectIds: \", projectIds)\n","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_crud.go#L268-L304","documentation":"DeleteAllPlansHandler (plans_crud.go:286) returns 500 when db.DeleteOwnerPlans(orgId, projectId, userId) fails to delete all plans owned by the user in the project. The operation is a bulk delete (DB rows plus likely per-plan directories), so the error propagates from either the SQL execution or an internal step inside DeleteOwnerPlans.","triggerScenarios":"POST/DELETE to the delete-all-plans route for a projectId where the underlying bulk DELETE statement errors — DB connection failure, SQL error in DeleteOwnerPlans, or an error deleting one of the plan directories inside the function.","commonSituations":"Database unavailable or connection pool exhausted; very large plan counts timing out; a single unreadable plan directory aborting the whole bulk operation; FK constraints if plans are referenced by other tables.","solutions":["Read the server log line 'Error deleting plans: <err>' to identify whether the failure is SQL-level or directory-level.","Retry the request — if it's a transient connection issue, the retry should succeed and is idempotent for already-deleted plans.","Check for foreign-key constraints referencing plans that block the bulk DELETE; add ON DELETE CASCADE or delete dependents first.","For large projects, chunk the deletion or add a statement timeout and delete in batches."],"exampleFix":"// before\nerr := db.DeleteOwnerPlans(auth.OrgId, projectId, auth.User.Id)\n// after\nerr := db.DeleteOwnerPlansBatch(ctx, auth.OrgId, projectId, auth.User.Id, 500) // delete in batches with retry","handlingStrategy":"retry","validationCode":"if err := db.Conn.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"database unavailable: %w\", err)\n}","typeGuard":"func isTransientDBErr(err error) bool {\n    var pgErr *pgconn.PgError\n    return errors.As(err, &pgErr) && pgconn.SafeToRetry(err)\n}","tryCatchPattern":"err := db.DeleteOwnerPlans(auth.OrgId, projectId, auth.User.Id)\nfor i := 0; i < 3 && isTransientDBErr(err); i++ {\n    time.Sleep(time.Duration(1<<i) * 100 * time.Millisecond)\n    err = db.DeleteOwnerPlans(auth.OrgId, projectId, auth.User.Id)\n}","preventionTips":["Retry transient DB failures with exponential backoff; the bulk delete is idempotent.","Add FK constraints with ON DELETE CASCADE so bulk deletes are not blocked.","Batch large deletions and set statement timeouts.","Monitor DB pool saturation and connection errors."],"tags":["database","go","http-500","bulk-delete"],"backgroundTag":"database-query-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"}