plandex-ai/plandex · error
error renaming plan: %v
Error message
error renaming plan: %v
What it means
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.
Source
Thrown at app/server/model/plan/tell_load.go:118
clients,
authVars,
req.Prompt,
active.SessionId,
active.Ctx,
)
if err != nil {
log.Printf("Error generating plan name: %v\n", err)
errCh <- fmt.Errorf("error generating plan name: %v", err)
return
}
err = db.WithTx(active.Ctx, "rename plan", func(tx *sqlx.Tx) error {
err := db.RenamePlan(planId, name, tx)
if err != nil {
log.Printf("Error renaming plan: %v\n", err)
return fmt.Errorf("error renaming plan: %v", err)
}
err = db.IncNumNonDraftPlans(currentUserId, tx)
if err != nil {
log.Printf("Error incrementing num non draft plans: %v\n", err)
return fmt.Errorf("error incrementing num non draft plans: %v", err)
}
return nil
})
if err != nil {
log.Printf("Error renaming plan: %v\n", err)
errCh <- fmt.Errorf("error renaming plan: %v", err)
return
}
}View on GitHub (pinned to e2d772072e)
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
Example fix
// before
db.WithTx(active.Ctx, "rename plan", func(tx *sqlx.Tx) error {
err := db.RenamePlan(planId, name, tx)
if err != nil {
return fmt.Errorf("error renaming plan: %v", err)
}
...
})
// after
db.WithTx(active.Ctx, "rename plan", func(tx *sqlx.Tx) error {
exists, err := db.PlanExists(currentOrgId, planId, tx)
if err != nil {
return fmt.Errorf("error checking plan: %v", err)
}
if !exists {
return fmt.Errorf("plan %s no longer exists (concurrently renamed)", planId)
}
if err := db.RenamePlan(planId, name, tx); err != nil {
return fmt.Errorf("error renaming plan: %v", err)
}
...
}) Defensive patterns
Strategy: try-catch
Validate before calling
// before invoking the load flow
plan, err := db.GetPlanSettings(plan)
if err != nil || plan == nil {
return fmt.Errorf("plan not found or unreadable")
}
if plan.Name != "draft" {
return nil // rename path will not run
}
if name == "" || len(name) > maxPlanNameLen {
return fmt.Errorf("generated plan name invalid")
} Type guard
func planIsDraft(p *types.Plan) bool {
return p != nil && p.Name == "draft"
} Try / catch
err = db.WithTx(active.Ctx, "rename plan", func(tx *sqlx.Tx) error {
if err := db.RenamePlan(planId, name, tx); err != nil {
return fmt.Errorf("error renaming plan: %w", err)
}
return nil
})
if err != nil {
log.Printf("Error renaming plan: %v", err)
if isTransientDBErr(err) { /* retry once */ }
return fmt.Errorf("error renaming plan: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error creating invite: %v
- error deleting invite: %v
- error accepting invite: %v
- error creating plan: %v
- error inserting lockable plan id: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/5ee757c552e81cbc.
Report an issue: GitHub.