{"record":{"id":"f1edeaaed521adae","repo":"plandex-ai/plandex","slug":"not-found-f1edea","errorCode":null,"errorMessage":"Not found","messagePattern":"Not found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"app/server/handlers/plans_crud.go","lineNumber":250,"sourceCode":"\n\tres, err := db.Conn.Exec(\"DELETE FROM plans WHERE id = $1\", planId)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error deleting plan: %v\\n\", err)\n\t\thttp.Error(w, \"Error deleting plan: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\trowsAffected, err := res.RowsAffected()\n\tif err != nil {\n\t\tlog.Printf(\"Error getting rows affected: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting rows affected: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif rowsAffected == 0 {\n\t\tlog.Println(\"Plan not found\")\n\t\thttp.Error(w, \"Not found\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\terr = db.DeletePlanDir(auth.OrgId, planId)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error deleting plan dir: %v\\n\", err)\n\t\thttp.Error(w, \"Error deleting plan dir: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully deleted plan\", planId)\n}\n\nfunc DeleteAllPlansHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received request for DeleteAllPlansHandler\")\n\n\tauth := Authenticate(w, r, true)","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_crud.go#L232-L268","documentation":"DeletePlanHandler (plans_crud.go:250) returns 404 'Not found' when the DELETE statement affected zero rows, meaning no plan row with the given planId existed in the plans table. Note: authorization already passed (the plan appeared to exist for this user), so this usually indicates a race or an ID mismatch rather than a normal missing-plan case.","triggerScenarios":"DELETE FROM plans WHERE id = $1 matches 0 rows: the plan was deleted by another user/request between authorizePlanDelete and the DELETE, the planId path variable is wrong or points to an already-purged plan, or the row lives in a different database/environment than expected.","commonSituations":"Double-clicking a delete button so the second request 404s; stale UI listing a plan deleted elsewhere; pointing a dev client at a prod (or empty) database; IDs from a different environment after a DB reset.","solutions":["Treat 404 as success on retry/delete flows — if the goal was deletion, the plan is already gone; refresh the plan list.","Verify the planId in the request URL matches an existing row (SELECT id FROM plans WHERE id = ...).","Confirm the server is connected to the expected database/environment (check DATABASE_URL / db config).","Add a UNIQUE guard or soft-delete flag if concurrent deletes of the same plan are common in your app."],"exampleFix":"// client-side before\nawait api.deletePlan(planId); // 404 throws\n// after\nconst res = await api.deletePlan(planId);\nif (res.status === 404) return; // already deleted — success for idempotent delete","handlingStrategy":"fallback","validationCode":"const exists = await fetch(`/api/plans/${planId}`).then(r => r.status !== 404);\nif (!exists) return; // nothing to delete","typeGuard":"func planExists(ctx context.Context, db *sql.DB, planId string) (bool, error) {\n    var one int\n    err := db.QueryRowContext(ctx, \"SELECT 1 FROM plans WHERE id = $1\", planId).Scan(&one)\n    if errors.Is(err, sql.ErrNoRows) { return false, nil }\n    return err == nil, err\n}","tryCatchPattern":"const res = await fetch(`/api/plans/${planId}`, { method: 'DELETE' });\nif (res.status === 404) {\n  // already deleted — treat as success in idempotent delete flows\n} else if (!res.ok) {\n  throw new Error(await res.text());\n}","preventionTips":["Design delete endpoints/clients to be idempotent — 404 on delete means success.","Refresh the plan list after deletion to avoid stale UI entries.","Guard against double-submit (disable the button while the request is in flight).","Confirm you are pointed at the correct environment/database."],"tags":["http-404","database","go","race-condition"],"backgroundTag":"resource-not-found-404","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"}