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

  1. Inspect the wrapped inner error (%v) and the 'Error renaming plan' log line to identify the root SQL failure
  2. Re-run the request — if it was a transient connection error the retry will recreate/rename the draft
  3. Check for a concurrent session operating on the same draft plan and serialize requests per user/plan
  4. Verify the plans table schema (name column uniqueness and length) matches db.RenamePlan's SQL
  5. 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

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


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/5ee757c552e81cbc. Report an issue: GitHub.