plandex-ai/plandex · error

panic in GetCurrentPlanState: %v\n%s

Error message

panic in GetCurrentPlanState: %v\n%s

What it means

GetCurrentPlanState runs four goroutines with per-goroutine recover. If the goroutine that fetches plan file results (only when params.PlanFileResults is nil) panics, the panic is logged with a stack trace, converted to this error, and returned to the caller.

Source

Thrown at app/server/db/result_helpers.go:155

		Contexts:                 contexts,
	}, nil
}

func GetCurrentPlanState(params CurrentPlanStateParams) (*shared.CurrentPlanState, error) {
	orgId := params.OrgId
	planId := params.PlanId

	var dbPlanFileResults []*PlanFileResult
	var convoMessageDescriptions []*shared.ConvoMessageDescription
	contextsByPath := map[string]*Context{}
	planApplies := []*shared.PlanApply{}
	errCh := make(chan error, 4)

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

			if err != nil {
				errCh <- fmt.Errorf("error getting plan file results: %v", err)
				return
			}
		} else {
			dbPlanFileResults = params.PlanFileResults
		}

		errCh <- nil
	}()

View on GitHub (pinned to e2d772072e)

Solutions

  1. If you already have results in memory, pass them via params.PlanFileResults to skip the disk load
  2. Use the logged stack trace to pinpoint the panicking line and fix the data or code
  3. Repair or remove corrupt result JSON files
  4. Upgrade the db package to a patched version
  5. Pre-populate CurrentPlanStateParams from GetFullCurrentPlanStateParams instead of passing a zero value

Example fix

// before
state, err := db.GetCurrentPlanState(db.CurrentPlanStateParams{})
// after
params, err := db.GetFullCurrentPlanStateParams(orgId, planId)
if err != nil {
	return nil, err
}
state, err := db.GetCurrentPlanState(params)
Defensive patterns

Strategy: validation

Validate before calling

func buildParams(orgId, planId string) (db.CurrentPlanStateParams, error) {
	if orgId == "" || planId == "" {
		return db.CurrentPlanStateParams{}, fmt.Errorf("orgId and planId required")
	}
	return db.GetFullCurrentPlanStateParams(orgId, planId)
}
// then pass the fully-populated params to GetCurrentPlanState

Type guard

func paramsComplete(p db.CurrentPlanStateParams) bool {
	return p.OrgId != "" && p.PlanId != "" && p.PlanFileResults != nil
}

Try / catch

state, err := db.GetCurrentPlanState(params)
if err != nil && strings.Contains(err.Error(), "panic in GetCurrentPlanState") {
	log.Printf("results goroutine panicked; stack in server log: %v", err)
	return nil, err
}

Prevention

When it happens

Trigger: Calling GetCurrentPlanState with params.PlanFileResults == nil so it loads from disk, and GetPlanFileResults panics — e.g. nil map write or nil deref on malformed result data.

Common situations: Corrupt result files on disk; a nil-pointer bug in the db helpers after a version change; zero-value CurrentPlanStateParams passed by mistake when caller intended to supply cached results.

Related errors


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