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
- If you already have results in memory, pass them via params.PlanFileResults to skip the disk load
- Use the logged stack trace to pinpoint the panicking line and fix the data or code
- Repair or remove corrupt result JSON files
- Upgrade the db package to a patched version
- 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
- Never pass a zero-value CurrentPlanStateParams; always populate cached sub-results when available
- Supply PlanFileResults explicitly to avoid a redundant disk load
- Keep the stack trace from the server log as the primary debugging artifact
- Re-verify stored result JSON integrity after crashes or upgrades
- Pin and test db package versions in CI with realistic data
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
- panic in UpdateContexts: %v\n%s
- panic in GetPlanConvo: %v\n%s
- panic in gitRemoveIndexLockFileIfExists: %v %s
- panic in DeleteDraftPlans: %v %s
- panic in GetFullCurrentPlanStateParams: %v\n%s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/dbcf57099982e346.
Report an issue: GitHub.