plandex-ai/plandex · error

error getting contexts or convo: %v

Error message

error getting contexts or convo: %v

What it means

SyncPlanTokens collects two results from its goroutines via a channel loop; if either goroutine reports an error (including the recovered panics from errors 452/453), this wrapper 'error getting contexts or convo' is returned. It means fetching the plan's contexts and/or conversation messages failed, so token totals cannot be computed and the branches row is left unsynced.

Source

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

	}()

	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("panic in SyncPlanTokens: %v\n%s", r, debug.Stack())
				errCh <- fmt.Errorf("panic in SyncPlanTokens: %v\n%s", r, debug.Stack())
				runtime.Goexit() // don't allow outer function to continue and double-send to channel
			}
		}()
		var err error
		convos, err = GetPlanConvo(orgId, planId)
		errCh <- err
	}()

	for i := 0; i < 2; i++ {
		err := <-errCh
		if err != nil {
			return fmt.Errorf("error getting contexts or convo: %v", err)
		}
	}

	contextTokens := 0
	for _, context := range contexts {
		contextTokens += context.NumTokens
	}

	convoTokens := 0
	for _, msg := range convos {
		convoTokens += msg.Tokens
	}

	_, err := Conn.Exec("UPDATE branches SET context_tokens = $1, convo_tokens = $2 WHERE plan_id = $3 AND name = $4", contextTokens, convoTokens, planId, branch)

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

View on GitHub (pinned to e2d772072e)

Solutions

  1. Unwrap the inner %v error: sql.ErrNoRows means the planId/orgId pair is invalid — validate the plan exists first
  2. Check DB connectivity and retry SyncPlanTokens if the inner error is transient (connection reset, context deadline)
  3. If the inner message is 'panic in SyncPlanTokens', fix the panicking code path per the logged stack trace
  4. Verify GetPlanContexts and GetPlanConvo handle the branch/plan state produced by rewind operations

Example fix

// before
return fmt.Errorf("error getting contexts or convo: %v", err)
// after
if errors.Is(err, sql.ErrNoRows) {
    return fmt.Errorf("plan %s not found for org %s: %w", planId, orgId, err)
}
return fmt.Errorf("error getting contexts or convo: %w", err)
Defensive patterns

Strategy: retry

Validate before calling

var plan Plan
if err := Conn.Get(&plan, "SELECT id FROM plans WHERE id = $1 AND org_id = $2", planId, orgId); err != nil {
    return fmt.Errorf("plan not found for org: %w", err)
}

Type guard

func planAccessible(orgId, planId string) bool {
    var exists bool
    _ = Conn.Get(&exists, "SELECT EXISTS(SELECT 1 FROM plans WHERE id = $1 AND org_id = $2)", planId, orgId)
    return exists
}

Try / catch

for attempt := 0; attempt < 2; attempt++ {
    err := SyncPlanTokens(orgId, planId, branch)
    if err == nil {
        break
    }
    if !errors.Is(err, sql.ErrNoRows) && attempt == 0 {
        time.Sleep(500 * time.Millisecond)
        continue
    }
    return err
}

Prevention

When it happens

Trigger: Either GetPlanContexts(orgId, planId, false, false) or GetPlanConvo(orgId, planId) returns an error — bad/missing planId, DB connection failure, permission/row-not-found, or a panic recovered into an error inside either goroutine.

Common situations: Called from RewindPlanHandler on a plan that was deleted mid-request; stale planId after a rewind removed records; Postgres unreachable; org-scoped query returning rows that fail to scan after schema changes.

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