plandex-ai/plandex · error

Error listing plans:

Error message

Error listing plans: 

What it means

ListPlansHandler (plans_crud.go:339) returns 500 when db.ListOwnedPlans(authorizedProjectIds, userId, false) fails to query the user's plans for the authorized projects. The error originates in the database layer — connection failure, SQL error, or scan error while reading rows.

Source

Thrown at app/server/handlers/plans_crud.go:339

	}

	authorizedProjectIds := []string{}
	for _, projectId := range projectIds {
		if authorizeProjectOptional(w, projectId, auth, false) {
			authorizedProjectIds = append(authorizedProjectIds, projectId)
		}
	}

	if len(authorizedProjectIds) == 0 {
		writePlans()
		return
	}

	plans, err := db.ListOwnedPlans(authorizedProjectIds, auth.User.Id, false)

	if err != nil {
		log.Printf("Error listing plans: %v\n", err)
		http.Error(w, "Error listing plans: "+err.Error(), http.StatusInternalServerError)
		return
	}

	for _, plan := range plans {
		apiPlans = append(apiPlans, plan.ToApi())
	}

	writePlans()
}

func ListArchivedPlansHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Received request for ListArchivedPlansHandler")
	auth := Authenticate(w, r, true)
	if auth == nil {
		return
	}

	projectIds := r.URL.Query()["projectId"]

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check the server log 'Error listing plans: <err>' for the underlying DB error and fix accordingly.
  2. Verify DB connectivity/pool health (max connections, idle timeouts) and that the DB is running.
  3. Confirm the plans schema matches the deployed code — run pending migrations.
  4. Retry the request for transient failures; add automatic retry with backoff for idempotent reads.

Example fix

// before
plans, err := db.ListOwnedPlans(authorizedProjectIds, auth.User.Id, false)
// after
plans, err := db.ListOwnedPlans(authorizedProjectIds, auth.User.Id, false)
if err != nil {
    if isTransient(err) { // e.g. pgconn.SafeToRetry
        plans, err = db.ListOwnedPlans(authorizedProjectIds, auth.User.Id, false)
    }
}
Defensive patterns

Strategy: retry

Validate before calling

if len(authorizedProjectIds) == 0 { return } // caller already guards this before querying
if err := db.Conn.PingContext(ctx); err != nil { return err }

Type guard

func isTransientDBErr(err error) bool {
    var pgErr *pgconn.PgError
    return errors.As(err, &pgErr) && pgconn.SafeToRetry(err)
}

Try / catch

plans, err := db.ListOwnedPlans(ids, userId, false)
if err != nil {
    if isTransientDBErr(err) {
        plans, err = db.ListOwnedPlans(ids, userId, false) // one bounded retry
    }
    if err != nil {
        http.Error(w, "Error listing plans", http.StatusInternalServerError)
        return
    }
}

Prevention

When it happens

Trigger: GET /plans?projectId=... with at least one authorized projectId, and the ListOwnedPlans SQL query fails: DB unreachable, connection pool exhausted, invalid query after a schema migration (renamed columns/table), or row-scan type mismatch.

Common situations: Database restart or network blip; deploying code against a mismatched schema (migration not applied); connection pool exhaustion under load; listing plans for many projects producing a query timeout.

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


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