plandex-ai/plandex · error

Error listing projects:

Error message

Error listing projects: 

What it means

ListProjectsHandler issues 'SELECT id, name FROM projects WHERE org_id = $1' against the shared db.Conn. Any error returned by database/sql Query — connection failure, bad SQL, missing table — is logged and returned as HTTP 500 with the driver's error text appended.

Source

Thrown at app/server/handlers/projects.go:96

	w.Write(bytes)

	log.Println("Successfully created project", projectId)
}

func ListProjectsHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Received request for ListProjectsHandler")

	auth := Authenticate(w, r, true)
	if auth == nil {
		return
	}

	rows, err := db.Conn.Query("SELECT id, name FROM projects WHERE org_id = $1", auth.OrgId)

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

	var projects []shared.Project

	for rows.Next() {
		var project shared.Project
		err := rows.Scan(&project.Id, &project.Name)
		if err != nil {
			log.Printf("Error scanning project: %v\n", err)
			http.Error(w, "Error scanning project: "+err.Error(), http.StatusInternalServerError)
			return
		}
		projects = append(projects, project)
	}

	bytes, err := json.Marshal(projects)
	if err != nil {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the appended driver error: 'connection refused' means DB is down/wrong host; 'relation "projects" does not exist' means run migrations.
  2. Verify Postgres is running and reachable from the server (psql with the same DSN).
  3. Check env/DSN configuration (host, port, user, password, dbname) for typos.
  4. Ensure migrations creating the projects table have been applied.
  5. If pool exhaustion, raise max_connections or fix leaked rows (note: this handler never calls rows.Close(), which can leak connections under load).

Example fix

// before
rows, err := db.Conn.Query("SELECT id, name FROM projects WHERE org_id = $1", auth.OrgId)
...
// after
rows, err := db.Conn.Query("SELECT id, name FROM projects WHERE org_id = $1", auth.OrgId)
if err != nil { ... }
defer rows.Close()
Defensive patterns

Strategy: retry

Validate before calling

if err := db.Conn.PingContext(ctx); err != nil {
	return fmt.Errorf("database unavailable: %w", err)
}

Try / catch

projects, err := client.ListProjects(ctx)
if err != nil {
	var apiErr *APIError
	if errors.As(err, &apiErr) && apiErr.StatusCode == 500 {
		return retryWithBackoff(ctx, 3, func() error { _, err = client.ListProjects(ctx); return err })
	}
	return err
}

Prevention

When it happens

Trigger: GET/POST to the list-projects endpoint after successful auth, when the DB query fails: Postgres unreachable, connection pool exhausted, projects table missing, or syntax/permission error on the query.

Common situations: Postgres down or restarted; wrong DATABASE_URL in server env; migrations not applied; too many open connections (max_connections exceeded); TLS/cert misconfiguration between server and DB.

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/ade02a547dab2155. Report an issue: GitHub.