{"record":{"id":"5ee757c552e81cbc","repo":"plandex-ai/plandex","slug":"error-renaming-plan-v-5ee757","errorCode":null,"errorMessage":"error renaming plan: %v","messagePattern":"error renaming plan: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/model/plan/tell_load.go","lineNumber":118,"sourceCode":"\t\t\t\t\tclients,\n\t\t\t\t\tauthVars,\n\t\t\t\t\treq.Prompt,\n\t\t\t\t\tactive.SessionId,\n\t\t\t\t\tactive.Ctx,\n\t\t\t\t)\n\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Printf(\"Error generating plan name: %v\\n\", err)\n\t\t\t\t\terrCh <- fmt.Errorf(\"error generating plan name: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\terr = db.WithTx(active.Ctx, \"rename plan\", func(tx *sqlx.Tx) error {\n\t\t\t\t\terr := db.RenamePlan(planId, name, tx)\n\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Printf(\"Error renaming plan: %v\\n\", err)\n\t\t\t\t\t\treturn fmt.Errorf(\"error renaming plan: %v\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\terr = db.IncNumNonDraftPlans(currentUserId, tx)\n\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Printf(\"Error incrementing num non draft plans: %v\\n\", err)\n\t\t\t\t\t\treturn fmt.Errorf(\"error incrementing num non draft plans: %v\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Printf(\"Error renaming plan: %v\\n\", err)\n\t\t\t\t\terrCh <- fmt.Errorf(\"error renaming plan: %v\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/tell_load.go#L100-L136","documentation":"This error wraps a failure from db.RenamePlan inside the 'rename plan' transaction (db.WithTx) that runs when a user's 'draft' plan is renamed to a generated name. Because RenamePlan is executed inside a transaction, any SQL error (syntax, constraint, connection) aborts the whole tx, and the underlying database error is wrapped with this message for the caller. It signals the plan row could not be renamed, so the draft-to-named-plan promotion did not complete.","triggerScenarios":"Calling the tell/load flow with plan.Name == \"draft\" when the underlying UPDATE of the plan row fails inside db.WithTx — e.g. DB connection dropped mid-transaction, plan row deleted by a concurrent session, unique name collision on the generated plan name, or a SQL error in db.RenamePlan.","commonSituations":"Two concurrent requests rename the same draft plan at once (one already renamed it, so the row no longer matches or the new unique name collides); transient Postgres/MySQL connection failures; generated plan names exceeding a column length limit; DB migrations out of sync with the model code.","solutions":["Inspect the wrapped inner error (%v) and the 'Error renaming plan' log line to identify the root SQL failure","Re-run the request — if it was a transient connection error the retry will recreate/rename the draft","Check for a concurrent session operating on the same draft plan and serialize requests per user/plan","Verify the plans table schema (name column uniqueness and length) matches db.RenamePlan's SQL","Confirm the generated name from model.GenPlanName is non-empty and within column limits before the tx"],"exampleFix":"// before\ndb.WithTx(active.Ctx, \"rename plan\", func(tx *sqlx.Tx) error {\n    err := db.RenamePlan(planId, name, tx)\n    if err != nil {\n        return fmt.Errorf(\"error renaming plan: %v\", err)\n    }\n    ...\n})\n// after\ndb.WithTx(active.Ctx, \"rename plan\", func(tx *sqlx.Tx) error {\n    exists, err := db.PlanExists(currentOrgId, planId, tx)\n    if err != nil {\n        return fmt.Errorf(\"error checking plan: %v\", err)\n    }\n    if !exists {\n        return fmt.Errorf(\"plan %s no longer exists (concurrently renamed)\", planId)\n    }\n    if err := db.RenamePlan(planId, name, tx); err != nil {\n        return fmt.Errorf(\"error renaming plan: %v\", err)\n    }\n    ...\n})","handlingStrategy":"try-catch","validationCode":"// before invoking the load flow\nplan, err := db.GetPlanSettings(plan)\nif err != nil || plan == nil {\n    return fmt.Errorf(\"plan not found or unreadable\")\n}\nif plan.Name != \"draft\" {\n    return nil // rename path will not run\n}\nif name == \"\" || len(name) > maxPlanNameLen {\n    return fmt.Errorf(\"generated plan name invalid\")\n}","typeGuard":"func planIsDraft(p *types.Plan) bool {\n    return p != nil && p.Name == \"draft\"\n}","tryCatchPattern":"err = db.WithTx(active.Ctx, \"rename plan\", func(tx *sqlx.Tx) error {\n    if err := db.RenamePlan(planId, name, tx); err != nil {\n        return fmt.Errorf(\"error renaming plan: %w\", err)\n    }\n    return nil\n})\nif err != nil {\n    log.Printf(\"Error renaming plan: %v\", err)\n    if isTransientDBErr(err) { /* retry once */ }\n    return fmt.Errorf(\"error renaming plan: %w\", err)\n}","preventionTips":["Check that the plan still exists and is still named 'draft' before entering the rename transaction","Validate the generated plan name (non-empty, length, charset) before the tx","Add unique-constraint-aware handling for generated names","Monitor DB connectivity and use bounded retries for transient errors","Serialize draft-rename operations per user to avoid concurrent renames"],"tags":["database","transaction","sql","rename"],"backgroundTag":"database-transaction-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"}