plandex-ai/plandex · error
error streaming plan %s: %v
Error message
error streaming plan %s: %v
What it means
During plan streaming, when the response stream to the client fails with an ApiError, the server logs 'Error streaming plan', sends an error notification, cancels/deletes the active plan, and marks the plan status as error in the database with the ApiError's message. This is the server-side bookkeeping entry for any streamed-plan failure (LLM errors, context issues, provider failures).
Source
Thrown at app/server/model/plan/state.go:65
log.Printf("apiErr: %v\n", apiErr)
if apiErr == nil {
log.Printf("Plan %s stream completed successfully", planId)
err := db.SetPlanStatus(planId, branch, shared.PlanStatusFinished, "")
if err != nil {
log.Printf("Error setting plan %s status to ready: %v\n", planId, err)
}
// cancel *after* the DeleteActivePlan call
// allows queued operations to complete
DeleteActivePlan(orgId, userId, planId, branch)
activePlan.CancelFn()
return
} else {
log.Printf("Error streaming plan %s: %v\n", planId, apiErr)
go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error streaming plan %s: %v", planId, apiErr))
err := db.SetPlanStatus(planId, branch, shared.PlanStatusError, apiErr.Msg)
if err != nil {
log.Printf("Error setting plan %s status to error: %v\n", planId, err)
}
log.Println("Sending error message to client")
activePlan.Stream(shared.StreamMessage{
Type: shared.StreamMessageError,
Error: apiErr,
})
activePlan.FlushStreamBuffer()
log.Println("Stopping any active summary stream")
activePlan.SummaryCancelFn()
log.Println("Waiting 100ms after streaming error before canceling active plan")
time.Sleep(100 * time.Millisecond)View on GitHub (pinned to e2d772072e)
Solutions
- Read apiErr.Msg in the logs / plan status for the underlying cause and fix that first
- Check provider API key validity and rate limits
- Retry the tell request after the transient provider issue resolves
- Ensure clients keep the connection alive (proxies/load balancers timing out long streams)
Example fix
// before: long streams killed by proxy timeouts
server { proxy_read_timeout 60s; }
// after: allow long LLM streams
server { proxy_read_timeout 1800s; proxy_buffering off; } Defensive patterns
Strategy: try-catch
Validate before calling
// before starting a long plan, verify connectivity to the LLM provider
resp, err := http.Get(providerHealthURL)
if err != nil || resp.StatusCode != 200 { return fmt.Errorf("provider unreachable; postpone plan") } Try / catch
err := streamPlan(...)
if apiErr, ok := err.(*shared.ApiError); ok {
log.Printf("plan %s stream failed: %s", planId, apiErr.Msg)
// plan status is already PlanStatusError; surface apiErr.Msg to the user
} Prevention
- Raise proxy/LB read timeouts for long streaming responses
- Keep provider API keys valid and rotated before expiry
- Add provider status monitoring and alerting
- Handle PlanStatusError client-side by showing apiErr.Msg and offering retry
When it happens
Trigger: model.ModelRequest or the stream fails mid-plan with any ApiError (auth failure, provider 429/5xx, invalid model config, canceled context); the subscriber goroutine in state.go catches it and tears down the plan via DeleteActivePlan + SetPlanStatus(PlanStatusError).
Common situations: Provider outages mid-stream; expired/invalid API keys; context canceled because the user stopped the plan; network interruption between server and LLM provider during long generations.
Related errors
- error creating chat completion stream: %w
- stream timed out due to inactivity. The model is not respond
- model stream ended unexpectedly: %w
- error receiving stream chunk: %w
- model stopped with error status | The model is not respondin
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/a034ca45b9c6be59.
Report an issue: GitHub.