{"record":{"id":"cb47fac857fc0944","repo":"plandex-ai/plandex","slug":"error-getting-pending-builds-by-path-v-s","errorCode":null,"errorMessage":"Error getting pending builds by path: %v\n%s","messagePattern":"Error getting pending builds by path: (.+?)\n(.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"critical","filePath":"app/server/model/plan/tell_build_pending.go","lineNumber":32,"sourceCode":"\tplan := state.plan\n\tplanId := plan.Id\n\tbranch := state.branch\n\tauth := state.auth\n\tclients := state.clients\n\tauthVars := state.authVars\n\tcurrentOrgId := state.currentOrgId\n\tcurrentUserId := state.currentUserId\n\tactive := GetActivePlan(planId, branch)\n\n\tif active == nil {\n\t\tlog.Printf(\"execTellPlan: Active plan not found for plan ID %s on branch %s\\n\", planId, branch)\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tlog.Printf(\"panic in queuePendingBuilds: %v\\n%s\", r, debug.Stack())\n\t\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"error getting pending builds by path: %v\", r))\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(\"Error getting pending builds by path: %v\\n%s\", r, debug.Stack()),\n\t\t\t}\n\t\t}\n\t}()\n\n\tpendingBuildsByPath, err := active.PendingBuildsByPath(auth.OrgId, auth.User.Id, state.convo)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting pending builds by path: %v\\n\", err)\n\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"error getting pending builds by path: %v\", err))\n\n\t\tactive.StreamDoneCh <- &shared.ApiError{\n\t\t\tType:   shared.ApiErrorTypeOther,\n\t\t\tStatus: http.StatusInternalServerError,\n\t\t\tMsg:    fmt.Sprintf(\"Error getting pending builds by path: %v\", err),","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/plan/tell_build_pending.go#L14-L50","documentation":"queuePendingBuilds has a deferred recover() that catches any panic while computing pending builds. The recovered value r is reported as \"Error getting pending builds by path: %v\\n%s\" (value plus stack trace), sent to error tracking and to the client via the plan's StreamDoneCh as a 500 ApiError. It indicates a programming panic (nil dereference, index out of range) inside PendingBuildsByPath or the surrounding queueing logic, not a normal error return.","triggerScenarios":"A nil pointer or out-of-range panic is raised during active.PendingBuildsByPath or subsequent build queueing after a tell stream finishes; the deferred recover converts it into this 500 ApiError pushed to StreamDoneCh.","commonSituations":"A nil convo or nil context passed into pending-build computation; concurrent modification of active plan state (map/race) between the tell stream goroutine and build goroutines; a bug introduced by a version upgrade in build-tracking code.","solutions":["Read the stack trace appended in the error message (the %s after \\n) to locate the panicking function and fix the nil/overflow condition.","Check for data races around the active plan struct — run the server with -race while reproducing.","Ensure state.convo and active plan fields are fully populated before queuePendingBuilds is invoked.","Report the panic with the full stack to Plandex maintainers if it comes from library code after an upgrade."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// on the server, run with race detection and validate inputs before queuePendingBuilds\nif state.convo == nil || active == nil {\n    log.Printf(\"queuePendingBuilds skipped: missing convo or active plan\")\n    return\n}","typeGuard":null,"tryCatchPattern":"// consumer side of StreamDoneCh\napiErr := <-active.StreamDoneCh\nif strings.HasPrefix(apiErr.Msg, \"Error getting pending builds by path\") {\n    stack := apiErr.Msg[strings.Index(apiErr.Msg, \"\\n\")+1:]\n    log.Printf(\"panic in pending builds, stack:\\n%s\", stack) // preserve stack for debugging\n    // retry the tell request once, then report with the stack\n}","preventionTips":["Run the server under go run -race in staging to catch the underlying races.","Keep plandex-server and plandex-shared versions in lockstep.","Never mutate active plan state from multiple goroutines without locking.","Capture and file the embedded stack trace whenever this 500 appears."],"tags":["go","panic","goroutine","internal-error"],"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"}