{"record":{"id":"7f53d0707b99156d","repo":"plandex-ai/plandex","slug":"panic-in-exectellplan-v-s","errorCode":null,"errorMessage":"Panic in execTellPlan: %v\n%s","messagePattern":"Panic in execTellPlan: (.+?)\n(.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"critical","filePath":"app/server/model/plan/tell_exec.go","lineNumber":114,"sourceCode":"\tunfinishedSubtaskReasoning := params.unfinishedSubtaskReasoning\n\n\tlog.Printf(\"[TellExec] Starting iteration %d for plan %s on branch %s\", iteration, plan.Id, branch)\n\n\tcurrentUserId := auth.User.Id\n\tcurrentOrgId := auth.OrgId\n\n\tactive := GetActivePlan(plan.Id, branch)\n\n\tif active == nil {\n\t\tlog.Printf(\"execTellPlan: Active plan not found for plan ID %s on branch %s\\n\", plan.Id, branch)\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlog.Printf(\"execTellPlan: Panic: %v\\n%s\\n\", r, string(debug.Stack()))\n\n\t\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"execTellPlan: Panic: %v\\n%s\", r, string(debug.Stack())))\n\n\t\t\tactive.StreamDoneCh <- &shared.ApiError{\n\t\t\t\tType:   shared.ApiErrorTypeOther,\n\t\t\t\tStatus: http.StatusInternalServerError,\n\t\t\t\tMsg:    fmt.Sprintf(\"Panic in execTellPlan: %v\\n%s\", r, string(debug.Stack())),\n\t\t\t}\n\t\t}\n\t}()\n\n\tif missingFileResponse == \"\" {\n\t\tlog.Println(\"Executing WillExecPlanHook\")\n\t\t_, apiErr := hooks.ExecHook(hooks.WillExecPlan, hooks.HookParams{\n\t\t\tAuth: auth,\n\t\t\tPlan: plan,\n\t\t})\n\n\t\tif apiErr != nil {\n\t\t\ttime.Sleep(100 * time.Millisecond)","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/tell_exec.go#L96-L132","documentation":"execTellPlan installs a deferred recover() so any panic during the tell-stream execution loop is converted into an ApiError pushed to StreamDoneCh with message \"Panic in execTellPlan: %v\\n%s\" (panic value plus stack trace), and is also reported to error tracking. It signals an unexpected programming fault (nil map access, index panic, type assertion failure) inside the plan's tell execution rather than a handled error path.","triggerScenarios":"Any unrecovered panic inside execTellPlan — typically nil pointer on state/settings/model config, index-out-of-range while slicing convo messages, or a failed type assertion on model responses — triggered via Tell, handleStreamFinished, or handleMissingFile.","commonSituations":"Model packs / settings returning nil coder after a config change; concurrent writes to the active plan map from multiple goroutines; a bug in prompt-building code hitting an empty slice after an upgrade.","solutions":["Use the stack trace in the message (after the newline) to pinpoint the panicking line and fix the nil/invalid state access.","Validate settings/model pack configuration — a missing coder model in the model pack is a common nil source.","Reproduce with -race to detect concurrent mutation of active plan state.","Escalate to Plandex maintainers with the full stack trace if the panic originates in framework code."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// validate model pack settings before Tell so nil coder cannot panic the executor\nif state.settings.GetModelPack().GetCoder() == nil {\n    return errors.New(\"model pack has no coder model configured\")\n}","typeGuard":null,"tryCatchPattern":"apiErr := <-active.StreamDoneCh\nif strings.HasPrefix(apiErr.Msg, \"Panic in execTellPlan\") {\n    stack := apiErr.Msg[strings.Index(apiErr.Msg, \"\\n\")+1:]\n    log.Printf(\"tell plan panicked:\\n%s\", stack)\n    // fall back: restart the tell from scratch rather than resuming corrupted stream state\n    return restartTell(planId, branch)\n}","preventionTips":["Always configure a coder model in every model pack you use.","Run with -race in CI/staging to surface concurrent state mutation early.","Pin matching versions of plandex-server and plandex-shared.","Report recurring panics to maintainers with the embedded stack trace."],"tags":["go","panic","goroutine","llm-stream"],"backgroundTag":"panic-recovered-to-500","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}