plandex-ai/plandex · error

error getting plan summaries: %v

Error message

error getting plan summaries: %v

What it means

This error is produced by the getPlanSummaries goroutine's recover handler: the goroutine that loads the plan's conversation summaries panicked. The recovered value is wrapped and sent on innerErrCh so loadTellPlan aborts cleanly rather than crashing the server.

Source

Thrown at app/server/model/plan/tell_load.go:246

					if err != nil {
						log.Printf("[TellLoad] Error storing user message: %v\n", err)
						innerErrCh <- fmt.Errorf("error storing user message: %v", err)
						return
					}

					UpdateActivePlan(planId, branch, func(ap *types.ActivePlan) {
						ap.MessageNum = num
					})
				}

				innerErrCh <- nil
			}()

			go func() {
				defer func() {
					if r := recover(); r != nil {
						log.Printf("panic in getPlanSummaries: %v\n%s", r, debug.Stack())
						innerErrCh <- fmt.Errorf("error getting plan summaries: %v", r)
						runtime.Goexit() // don't allow outer function to continue and double-send to channel
					}
				}()

				var convoMessageIds []string

				for _, convoMessage := range convo {
					convoMessageIds = append(convoMessageIds, convoMessage.Id)
				}

				log.Println("getting plan summaries")
				log.Println("convoMessageIds:", convoMessageIds)

				res, err := db.GetPlanSummaries(planId, convoMessageIds)
				if err != nil {
					log.Printf("Error getting plan summaries: %v\n", err)
					innerErrCh <- fmt.Errorf("error getting plan summaries: %v", err)
					return

View on GitHub (pinned to e2d772072e)

Solutions

  1. Inspect the 'panic in getPlanSummaries' stack trace to find the exact deref site
  2. Skip convo messages with empty/nil Ids when building convoMessageIds
  3. Validate GetPlanSummaries results before indexing summaries[len-1]
  4. Run with -race to check for concurrent mutation of the shared convo slice

Example fix

// before
for _, convoMessage := range convo {
    convoMessageIds = append(convoMessageIds, convoMessage.Id)
}
// after
for _, convoMessage := range convo {
    if convoMessage.Id != "" {
        convoMessageIds = append(convoMessageIds, convoMessage.Id)
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

if len(convo) == 0 {
    log.Println("no convo messages; skipping summaries fetch")
    return nil
}
for _, m := range convo {
    if m.Id == "" {
        return fmt.Errorf("convo message missing Id; cannot fetch summaries safely")
    }
}

Type guard

func hasValidConvoIds(convo []db.ConvoMessage) bool {
    for _, m := range convo {
        if m.Id == "" {
            return false
        }
    }
    return true
}

Try / catch

if err := <-innerErrCh; err != nil && strings.HasPrefix(err.Error(), "error getting plan summaries:") {
    // panic-recovery path — stack already logged; proceed with empty summaries or abort
    return err
}

Prevention

When it happens

Trigger: A panic inside the goroutine guarded at tell_load.go:246 — e.g., nil dereference while building convoMessageIds from convo entries with nil pointers, or a panic inside db.GetPlanSummaries(planId, convoMessageIds) or while reading the last summary's .Summary field.

Common situations: Corrupted convo entries with missing Ids or nil fields in the DB; convo slice mutated concurrently by another goroutine; nil summaries entry accessed via summaries[len-1].Summary after a partial query result.

Related errors


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