plandex-ai/plandex · error

error setting plan status: %v

Error message

error setting plan status: %v

What it means

SetPlanStatus writes status and error text to the branches row via UPDATE branches SET status = $1, error = $2 WHERE plan_id = $3 AND name = $4. This wrapper fires when that UPDATE fails at the DB level. It is called from many places (streams, builds, tell/exec handlers), so a failure here typically means plan lifecycle state cannot be persisted while other plan operations may be in flight.

Source

Thrown at app/server/db/plan_helpers.go:268

}

func GetPlan(planId string) (*Plan, error) {
	var plan Plan

	err := Conn.Get(&plan, "SELECT * FROM plans WHERE id = $1", planId)

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

	return &plan, nil
}

func SetPlanStatus(planId, branch string, status shared.PlanStatus, errStr string) error {
	_, err := Conn.Exec("UPDATE branches SET status = $1, error = $2 WHERE plan_id = $3 AND name = $4", status, errStr, planId, branch)

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

	return nil
}

func RenamePlan(planId string, name string, tx *sqlx.Tx) error {
	var err error
	if tx == nil {
		_, err = Conn.Exec("UPDATE plans SET name = $1 WHERE id = $2", name, planId)
	} else {
		_, err = tx.Exec("UPDATE plans SET name = $1 WHERE id = $2", name, planId)
	}

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

	return nil

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check the inner error for connection/lock issues and verify DB health and pool sizing
  2. Confirm the PlanStatus value being set is valid for the branches.status column type/enum
  3. Ensure the planId+branch pair identifies an existing branches row; missing rows don't error but stale/wrong pairs may cause downstream constraint failures
  4. Add retry with backoff around SetPlanStatus for transient connection errors, especially in stream-finish paths

Example fix

// before
_, err := Conn.Exec("UPDATE branches SET status = $1, error = $2 WHERE plan_id = $3 AND name = $4", status, errStr, planId, branch)
// after
res, err := Conn.Exec("UPDATE branches SET status = $1, error = $2 WHERE plan_id = $3 AND name = $4", status, errStr, planId, branch)
if err == nil {
    if n, _ := res.RowsAffected(); n == 0 {
        err = fmt.Errorf("no branches row for plan %s branch %s", planId, branch)
    }
}
Defensive patterns

Strategy: retry

Validate before calling

var exists bool
if err := Conn.Get(&exists, "SELECT EXISTS(SELECT 1 FROM branches WHERE plan_id = $1 AND name = $2)", planId, branch); err != nil || !exists {
    return fmt.Errorf("branch %s not found for plan %s", branch, planId)
}

Type guard

func branchRowExists(planId, branch string) bool {
    var exists bool
    _ = Conn.Get(&exists, "SELECT EXISTS(SELECT 1 FROM branches WHERE plan_id = $1 AND name = $2)", planId, branch)
    return exists
}

Try / catch

err := SetPlanStatus(planId, branch, shared.PlanStatusRunning, "")
if err != nil {
    if isTransientDBError(err) {
        time.Sleep(time.Second)
        err = SetPlanStatus(planId, branch, shared.PlanStatusRunning, "")
    }
    if err != nil {
        log.Printf("status update failed for plan %s/%s: %v", planId, branch, err)
    }
}

Prevention

When it happens

Trigger: The branches UPDATE errors: DB connection dropped mid-stream, branches row missing (no rows affected — silent, but constraint errors possible), status enum value not matching the column type, or table lock timeout under concurrent stream updates.

Common situations: Many concurrent model streams updating status on the same branch causing lock contention; passing a PlanStatus value not accepted by the DB column type; Postgres restart during a long-running Build; wrong branch name combined with a schema constraint.

Related errors


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