plandex-ai/plandex · error
Error checking if plan exists:
Error message
Error checking if plan exists:
What it means
CreatePlanHandler returns this 500 when the sqlx query that counts existing plans with the same project_id/owner_id/name fails. It is part of the duplicate-name auto-suffix loop, so the handler cannot proceed to create the plan. It surfaces the underlying database error text in the response body.
Source
Thrown at app/server/handlers/plans_crud.go:90
if name == "draft" {
// delete any existing draft plans
err = db.DeleteDraftPlans(auth.OrgId, projectId, auth.User.Id)
if err != nil {
log.Printf("Error deleting draft plans: %v\n", err)
http.Error(w, "Error deleting draft plans: "+err.Error(), http.StatusInternalServerError)
return
}
} else {
i := 2
originalName := name
for {
var count int
err := db.Conn.Get(&count, "SELECT COUNT(*) FROM plans WHERE project_id = $1 AND owner_id = $2 AND name = $3", projectId, auth.User.Id, name)
if err != nil {
log.Printf("Error checking if plan exists: %v\n", err)
http.Error(w, "Error checking if plan exists: "+err.Error(), http.StatusInternalServerError)
return
}
if count == 0 {
break
}
name = originalName + "." + fmt.Sprint(i)
i++
}
}
plan, err := db.CreatePlan(r.Context(), auth.OrgId, projectId, auth.User.Id, name)
if err != nil {
log.Printf("Error creating plan: %v\n", err)
http.Error(w, "Error creating plan: "+err.Error(), http.StatusInternalServerError)
returnView on GitHub (pinned to e2d772072e)
Solutions
- Check server logs for the wrapped database error text appended after the prefix to identify the root cause
- Verify the Postgres instance is reachable and DATABASE_URL is correct (try psql with the same DSN)
- Run migrations to ensure the plans table exists with project_id, owner_id and name columns
- Check connection pool settings/limits (max conns, idle timeout) and restart saturated database connections
Example fix
// before
err := db.Conn.Get(&count, "SELECT COUNT(*) FROM plans WHERE project_id = $1 AND owner_id = $2 AND name = $3", projectId, auth.User.Id, name)
// after
if db.Conn == nil { http.Error(w, "database not initialized", http.StatusInternalServerError); return }
err := db.Conn.Get(&count, "SELECT COUNT(*) FROM plans WHERE project_id = $1 AND owner_id = $2 AND name = $3", projectId, auth.User.Id, name) Defensive patterns
Strategy: retry
Validate before calling
if err := db.Conn.Ping(); err != nil { return fmt.Errorf("database unreachable: %w", err) } Type guard
func isDBError(err error) bool { var pgErr *pgconn.PgError; return errors.As(err, &pgErr) } Try / catch
if err := db.Conn.Get(&count, q, args...); err != nil {
if isTransientDBErr(err) { /* backoff and retry once */ }
log.Printf("Error checking if plan exists: %v\n", err)
http.Error(w, "Error checking if plan exists", http.StatusInternalServerError)
return
} Prevention
- Ping or health-check the database before serving requests and on startup
- Keep migrations applied so plans table/columns exist in every environment
- Set sane connection pool limits and idle timeouts to avoid stale connections
- Monitor Postgres availability and alert on connection errors
When it happens
Trigger: POST to create a plan with a non-empty name (not 'draft') while db.Conn.Get on the plans table errors: plans table missing/migrated differently, database unreachable, connection pool exhausted, or a schema/type mismatch binding the count into int.
Common situations: Postgres not running or wrong DATABASE_URL after a deploy; partial migration leaving plans table columns missing (e.g. owner_id); DB connection dropped mid-request (TLS timeout, restart); replica failover.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- error creating plan: %v
- error inserting lockable plan id: %v
- error listing plans: %v
- error updating user num_non_draft_plans: %v
- error deleting draft plans: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/f44882ffe468a9de.
Report an issue: GitHub.