{"record":{"id":"4f7337ab4c14907e","repo":"plandex-ai/plandex","slug":"panic-in-rejectallresults-v-n-s","errorCode":null,"errorMessage":"panic in RejectAllResults: %v\\n%s","messagePattern":"panic in RejectAllResults: (.+?)\\\\n(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/result_helpers.go","lineNumber":813,"sourceCode":"\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error reading results dir: %v\", err)\n\t}\n\n\terrCh := make(chan error, len(files))\n\tnow := time.Now()\n\n\tfor _, file := range files {\n\t\tresultId := strings.TrimSuffix(file.Name(), \".json\")\n\n\t\tgo func(resultId string) {\n\t\t\tdefer func() {\n\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\tlog.Printf(\"panic in RejectAllResults: %v\\n%s\", r, debug.Stack())\n\t\t\t\t\terrCh <- fmt.Errorf(\"panic in RejectAllResults: %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\t\t\terr := RejectPlanFile(orgId, planId, resultId, now)\n\n\t\t\tif err != nil {\n\t\t\t\terrCh <- fmt.Errorf(\"error rejecting result: %v\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\terrCh <- nil\n\t\t}(resultId)\n\t}\n\n\tfor i := 0; i < len(files); i++ {\n\t\terr := <-errCh\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error rejecting plan: %v\", err)","sourceCodeStart":795,"sourceCodeEnd":831,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/result_helpers.go#L795-L831","documentation":"RejectAllResults spawns a goroutine per result file; each goroutine has a recover() defer that converts a panic into this error message (including a stack dump), logs it, and sends it on errCh before calling runtime.Goexit(). This message means RejectPlanFile (or nearby code) panicked while rejecting a result.","triggerScenarios":"A nil pointer dereference or index-out-of-range inside RejectPlanFile/org/plan/result handling; unexpected nil result data; any runtime panic raised inside the spawned goroutine while rejecting a specific resultId.","commonSituations":"Corrupt or hand-edited result JSON causing unexpected nil fields dereferenced downstream; concurrent mutation of shared plan state across goroutines; regressions in RejectPlanFile after refactors surfacing only under real data.","solutions":["Read the logged stack trace (also embedded in the error) to locate the panicking line in RejectPlanFile","Fix the nil-dereference/race at the identified location; guard nil result fields before use","Re-run RejectAllResults after the fix; only the panicking resultId failed, others were processed","Add a unit test reproducing the corrupt/edge-case result file"],"exampleFix":"// before: panic on nil inside RejectPlanFile\npath := result.ToApi().Path\n// after: guard nil\ntoApi := result.ToApi()\nif toApi == nil || toApi.Path == \"\" {\n    return fmt.Errorf(\"result %s has no path\", resultId)\n}\npath := toApi.Path","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func safeReject(orgId, planId, resultId string, now time.Time) (err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"panic in RejectPlanFile(%s): %v\\n%s\", resultId, r, debug.Stack())\n        }\n    }()\n    return RejectPlanFile(orgId, planId, resultId, now)\n}","tryCatchPattern":"go func(resultId string) {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Printf(\"panic in RejectAllResults: %v\\n%s\", r, debug.Stack())\n            errCh <- fmt.Errorf(\"panic in RejectAllResults: %v\\n%s\", r, debug.Stack())\n            runtime.Goexit()\n        }\n    }()\n    _ = RejectPlanFile(orgId, planId, resultId, now)\n}(resultId)","preventionTips":["Guard nil fields on PlanFileResult before dereferencing (ToApi/Path)","Add -race test runs for code that mutates plan state across goroutines","Unit-test RejectPlanFile with corrupt/minimal JSON fixtures","Keep recover()+Goexit pattern consistent in every spawned goroutine"],"tags":["go","panic","concurrency","goroutine"],"backgroundTag":"goroutine-panic-recovered","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}