{"record":{"id":"5d541b589474a433","repo":"plandex-ai/plandex","slug":"panic-getting-plan-settings-v-s","errorCode":null,"errorMessage":"panic getting plan settings: %v\n%s","messagePattern":"panic getting plan settings: (.+?)\n(.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/model/plan/tell_load.go","lineNumber":73,"sourceCode":"\n\tdb.ExecRepoOperation(db.ExecRepoOperationParams{\n\t\tOrgId:    auth.OrgId,\n\t\tUserId:   auth.User.Id,\n\t\tPlanId:   planId,\n\t\tBranch:   branch,\n\t\tScope:    lockScope,\n\t\tCtx:      active.Ctx,\n\t\tCancelFn: active.CancelFn,\n\t\tReason:   \"load tell plan\",\n\t}, func(repo *db.GitRepo) error {\n\t\terrCh := make(chan error, 4)\n\n\t\t// get name for plan and rename if it's a draft\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(\"panic getting plan settings: %v\\n%s\", r, debug.Stack())\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\n\t\t\tres, err := db.GetPlanSettings(plan)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error getting plan settings: %v\\n\", err)\n\t\t\t\terrCh <- fmt.Errorf(\"error getting plan settings: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tsettings = res\n\n\t\t\torgUserConfigRes, err := db.GetOrgUserConfig(auth.User.Id, auth.OrgId)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"Error getting org user config: %v\\n\", err)\n\t\t\t\terrCh <- fmt.Errorf(\"error getting org user config: %v\", err)\n\t\t\t\treturn\n\t\t\t}","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/tell_load.go#L55-L91","documentation":"This error is produced when the goroutine that fetches plan settings (db.GetPlanSettings) panics; the deferred recover converts the panic into an error sent on errCh. debug.Stack() is appended so the developer sees the panic site. runtime.Goexit stops the goroutine to avoid double-sending on the channel.","triggerScenarios":"db.GetPlanSettings panics — typically a nil pointer inside settings loading (nil plan fields, nil DB handle, nil embedded config dereference) or an unexpected data shape from the database.","commonSituations":"Corrupted or partially-migrated plan settings row missing required JSON fields; DB connection closed mid-query causing nil deref downstream; concurrent plan mutation while settings load.","solutions":["Read the stack trace after 'panic getting plan settings' to find the nil deref source","Inspect the plan's settings row in the DB for missing/invalid fields and repair or reset them","Check DB connectivity and that the plans/settings schema is fully migrated","Patch GetPlanSettings to nil-check before dereferencing"],"exampleFix":"// before\nres, err := db.GetPlanSettings(plan) // panics on nil plan.ModelPack\n// after\nif plan == nil || plan.Id == \"\" {\n    errCh <- fmt.Errorf(\"cannot load settings: plan is nil\")\n    return\n}\nres, err := db.GetPlanSettings(plan)","handlingStrategy":"try-catch","validationCode":"// ensure plan and its required fields exist before loading settings\nif plan == nil || plan.Id == \"\" {\n    return errors.New(\"plan is nil or has no id; cannot load settings\")\n}","typeGuard":null,"tryCatchPattern":"select {\ncase err := <-errCh:\n    if strings.HasPrefix(err.Error(), \"panic getting plan settings:\") {\n        // log stack trace, reset plan settings row to defaults, retry once\n    }\ncase res := <-resCh:\n    settings = res\n}","preventionTips":["Nil-check plan fields inside GetPlanSettings before dereferencing","Validate settings JSON shape on read to avoid nil maps/pointers","Keep schema migrations in sync with the settings struct","Watch 'panic in getPlanSettings' logs for recurring stack traces"],"tags":["panic","database","plan-settings","recovery"],"backgroundTag":"nil-pointer-panic","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"}