plandex-ai/plandex · critical

Error getting pending builds by path: %v %s

Error message

Error getting pending builds by path: %v
%s

What it means

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.

Source

Thrown at app/server/model/plan/tell_build_pending.go:32

	plan := state.plan
	planId := plan.Id
	branch := state.branch
	auth := state.auth
	clients := state.clients
	authVars := state.authVars
	currentOrgId := state.currentOrgId
	currentUserId := state.currentUserId
	active := GetActivePlan(planId, branch)

	if active == nil {
		log.Printf("execTellPlan: Active plan not found for plan ID %s on branch %s\n", planId, branch)
		return
	}

	defer func() {
		if r := recover(); r != nil {
			log.Printf("panic in queuePendingBuilds: %v\n%s", r, debug.Stack())
			go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error getting pending builds by path: %v", r))
			active.StreamDoneCh <- &shared.ApiError{
				Type:   shared.ApiErrorTypeOther,
				Status: http.StatusInternalServerError,
				Msg:    fmt.Sprintf("Error getting pending builds by path: %v\n%s", r, debug.Stack()),
			}
		}
	}()

	pendingBuildsByPath, err := active.PendingBuildsByPath(auth.OrgId, auth.User.Id, state.convo)

	if err != nil {
		log.Printf("Error getting pending builds by path: %v\n", err)
		go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error getting pending builds by path: %v", err))

		active.StreamDoneCh <- &shared.ApiError{
			Type:   shared.ApiErrorTypeOther,
			Status: http.StatusInternalServerError,
			Msg:    fmt.Sprintf("Error getting pending builds by path: %v", err),

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the stack trace appended in the error message (the %s after \n) to locate the panicking function and fix the nil/overflow condition.
  2. Check for data races around the active plan struct — run the server with -race while reproducing.
  3. Ensure state.convo and active plan fields are fully populated before queuePendingBuilds is invoked.
  4. Report the panic with the full stack to Plandex maintainers if it comes from library code after an upgrade.
Defensive patterns

Strategy: try-catch

Validate before calling

// on the server, run with race detection and validate inputs before queuePendingBuilds
if state.convo == nil || active == nil {
    log.Printf("queuePendingBuilds skipped: missing convo or active plan")
    return
}

Try / catch

// consumer side of StreamDoneCh
apiErr := <-active.StreamDoneCh
if strings.HasPrefix(apiErr.Msg, "Error getting pending builds by path") {
    stack := apiErr.Msg[strings.Index(apiErr.Msg, "\n")+1:]
    log.Printf("panic in pending builds, stack:\n%s", stack) // preserve stack for debugging
    // retry the tell request once, then report with the stack
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/cb47fac857fc0944. Report an issue: GitHub.