{"record":{"id":"e9b837d65bc1ff94","repo":"plandex-ai/plandex","slug":"error-getting-plan-settings-v-e9b837","errorCode":null,"errorMessage":"error getting plan settings: %v","messagePattern":"error getting plan settings: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/model/plan/build_load.go","lineNumber":72,"sourceCode":"\t\t\t\t\truntime.Goexit() // don't allow outer function to continue and double-send to channel\n\t\t\t\t}\n\t\t\t}()\n\t\t\tres, err := db.GetPlanContexts(auth.OrgId, plan.Id, true, false)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error getting plan modelContext: %v\\n\", err)\n\t\t\t\terrCh <- fmt.Errorf(\"error getting plan modelContext: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tmodelContext = res\n\n\t\t\terrCh <- nil\n\t\t}()\n\n\t\tgo func() {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tlog.Printf(\"panic in getPlanSettings: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\terrCh <- fmt.Errorf(\"error getting plan settings: %v\", r)\n\t\t\t\t\truntime.Goexit() // don't allow outer function to continue and double-send to channel\n\t\t\t\t}\n\t\t\t}()\n\t\t\tres, err := active.PendingBuildsByPath(auth.OrgId, auth.User.Id, nil)\n\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error getting pending builds by path: %v\\n\", err)\n\t\t\t\terrCh <- fmt.Errorf(\"error getting pending builds by path: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpendingBuildsByPath = res\n\n\t\t\terrCh <- nil\n\t\t}()\n\n\t\tgo func() {\n\t\t\tdefer func() {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/build_load.go#L54-L90","documentation":"Despite the 'plan settings' wording, this error is the panic-recovery branch of the goroutine that calls active.PendingBuildsByPath in loadPendingBuilds (build_load.go). The defer/recover block catches any panic (nil map write, nil pointer dereference, etc.) inside that goroutine and reports it as 'error getting plan settings: %v' with the recovered value, then calls runtime.Goexit to avoid double-sending on errCh. So seeing this message means the pending-builds goroutine panicked, not that settings failed. The recovered value after '%v' is the panic cause.","triggerScenarios":"Any panic inside the goroutine that wraps active.PendingBuildsByPath(orgId, userId, nil) - typically a nil receiver/plan-state field (e.g. 'active' or an internal map is nil because activatePlan failed upstream) or an unexpected type assertion while computing pending builds by path.","commonSituations":"activatePlan on line 23 failed (its error is only logged, not returned) leaving 'active' partially initialized; concurrent mutation of plan state; a bug triggered by a plan with zero pending builds or an unusual branch state; running a server build with mismatched plandex-server/shared versions.","solutions":["Check server logs for 'panic in getPlanSettings' followed by the stack trace - it identifies the exact nil dereference or assertion that panicked.","Check the log lines just before it for 'Error activating plan' - a failed activatePlan leaves 'active' partially initialized; fix that activation error first.","Upgrade plandex-server (and plandex CLI) to matching latest versions; this panic path was likely fixed in newer releases.","Retry the operation after confirming the plan/branch state is valid (plandex branches, plandex builds).","If reproducible, capture the stack trace and report it to Plandex - a panic here is an internal bug, not user error."],"exampleFix":"// before (server code that lets a failed activation produce a nil-dependent panic)\nactive, err := activatePlan(clients, plan, branch, auth, \"\", true, false, sessionId)\nif err != nil {\n    log.Printf(\"Error activating plan: %v\\n\", err)\n}\n// after\nactive, err := activatePlan(clients, plan, branch, auth, \"\", true, false, sessionId)\nif err != nil {\n    errCh <- fmt.Errorf(\"error activating plan: %v\", err)\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// before triggering the build, confirm the plan activated cleanly\n// plandex ps --plan <planId>   -> plan exists and branch is valid\n// check server logs for 'Error activating plan' before/at request time","typeGuard":null,"tryCatchPattern":"err := loadPlanBuild(planId)\nif err != nil {\n    if strings.Contains(err.Error(), \"error getting plan settings\") {\n        // ambiguous message: check server logs for 'panic in getPlanSettings'\n        // + stack trace to confirm it was a panic in the pending-builds goroutine,\n        // then retry or report upstream with the stack\n        return fmt.Errorf(\"internal server panic while loading plan: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep plandex-server and plandex CLI on matching versions to avoid state-shape mismatches that panic.","Check server logs for activation errors; a failed activatePlan is the usual precursor to this panic.","Avoid concurrent operations on the same plan/branch that race on shared state.","Report any 'panic in getPlanSettings' stack trace upstream - it indicates a server bug, not user error."],"tags":["go","panic","concurrency","pending-builds","plandex"],"backgroundTag":"unexpected-panic-recovered","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"}