plandex-ai/plandex · error

error getting plan config: %v

Error message

error getting plan config: %v

What it means

GetPlanConfig wraps a failure of Conn.Get(&config, "SELECT plan_config FROM plans WHERE id = $1", planId) with this message. Because sqlx Get requires exactly one row, this error fires both for a nonexistent planId (sql.ErrNoRows) and for genuine query/scan failures.

Source

Thrown at app/server/db/plan_config_helpers.go:18

package db

import (
	"fmt"

	shared "plandex-shared"

	"github.com/jmoiron/sqlx"
)

func GetPlanConfig(planId string) (*shared.PlanConfig, error) {
	query := "SELECT plan_config FROM plans WHERE id = $1"

	var config shared.PlanConfig
	err := Conn.Get(&config, query, planId)

	if err != nil {
		return nil, fmt.Errorf("error getting plan config: %v", err)
	}

	return &config, nil
}

func StorePlanConfig(planId string, config *shared.PlanConfig) error {
	query := `
		UPDATE plans 
		SET plan_config = $1
		WHERE id = $2
	`

	_, err := Conn.Exec(query, config, planId)

	if err != nil {
		return fmt.Errorf("error storing plan config: %v", err)
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the wrapped cause: 'sql: no rows in result set' means the planId doesn't exist — verify the plan exists before loading and return 404 to the client
  2. Check that the plan belongs to the caller's org/project if the id comes from user input
  3. If the cause is a scan/JSON error, inspect the plans.plan_config value for corruption and fix the data
  4. For connection errors, verify DATABASE_URL and Postgres health, then retry

Example fix

// before
config, err := GetPlanConfig(planId)
// after: distinguish not-found from real failures
config, err := GetPlanConfig(planId)
if err != nil {
    if strings.Contains(err.Error(), "no rows in result set") {
        http.Error(w, "plan not found", http.StatusNotFound)
        return
    }
    http.Error(w, "internal error", http.StatusInternalServerError)
    return
}
Defensive patterns

Strategy: try-catch

Validate before calling

var exists bool
err := Conn.Get(&exists, "SELECT EXISTS(SELECT 1 FROM plans WHERE id=$1)", planId)
if err != nil || !exists {
    // return 404 before calling GetPlanConfig
}

Try / catch

config, err := GetPlanConfig(planId)
if err != nil {
    if strings.Contains(err.Error(), "no rows in result set") {
        http.Error(w, "plan not found", http.StatusNotFound)
        return
    }
    log.Printf("GetPlanConfig: %v", err)
    http.Error(w, "internal error", http.StatusInternalServerError)
    return
}

Prevention

When it happens

Trigger: LoadContexts/UpdateContexts/GetPlanConfigHandler pass a planId that doesn't exist in plans (most common: sql: no rows in result set), the DB is unreachable, or plan_config cannot be scanned into shared.PlanConfig (malformed JSON in the column).

Common situations: Client references a deleted plan; stale plan id cached in the UI; plan row deleted mid-session; database migrated so plan_config column type changed; corrupted JSONB value.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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