{"record":{"id":"4464fafe6e29dfc4","repo":"plandex-ai/plandex","slug":"model-stream-ended-unexpectedly-w","errorCode":null,"errorMessage":"model stream ended unexpectedly: %w","messagePattern":"model stream ended unexpectedly: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/model/client_stream.go","lineNumber":143,"sourceCode":"\t\t\tlog.Println(\"Stream canceled\")\n\t\t\treturn accumulator.Result(true, streamCtx.Err()), streamCtx.Err()\n\t\tcase <-timer.C:\n\t\t\tlog.Println(\"Stream timed out due to inactivity\")\n\t\t\tif streamFinished {\n\t\t\t\tlog.Println(\"Stream finished—timed out waiting for usage chunk\")\n\t\t\t\treturn accumulator.Result(false, nil), nil\n\t\t\t} else {\n\t\t\t\tlog.Println(\"Stream timed out due to inactivity\")\n\t\t\t\treturn accumulator.Result(true, fmt.Errorf(\"stream timed out due to inactivity. The model is not responding.\")), nil\n\t\t\t}\n\t\tdefault:\n\t\t\tresponse, err := stream.Recv()\n\t\t\tif err == io.EOF {\n\t\t\t\tif streamFinished {\n\t\t\t\t\treturn accumulator.Result(false, nil), nil\n\t\t\t\t}\n\n\t\t\t\terr = fmt.Errorf(\"model stream ended unexpectedly: %w\", err)\n\t\t\t\treturn accumulator.Result(true, err), err\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"error receiving stream chunk: %w\", err)\n\t\t\t\treturn accumulator.Result(true, err), err\n\t\t\t}\n\n\t\t\tif response.ID != \"\" {\n\t\t\t\taccumulator.SetGenerationId(response.ID)\n\t\t\t}\n\n\t\t\tif !receivedFirstChunk {\n\t\t\t\treceivedFirstChunk = true\n\t\t\t\taccumulator.SetFirstTokenAt(time.Now())\n\t\t\t}\n\n\t\t\tif !timer.Stop() {\n\t\t\t\t<-timer.C","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/model/client_stream.go#L125-L161","documentation":"stream.Recv() returned io.EOF before the stream was marked finished (no finish-reason/usage chunk had arrived). The library treats a clean EOF at this point as an abnormal termination: the model closed the stream without a proper completion signal. The error is attached to the accumulated partial result and also returned.","triggerScenarios":"Provider closes the connection after sending some chunks but before a chunk with FinishReason (and the expected usage chunk) arrives; Recv returns io.EOF with streamFinished == false.","commonSituations":"Provider-side truncation (content filter, max output length enforced at proxy), LiteLLM proxy dropping the upstream connection, load balancer idle cutoff, provider aborting the request server-side.","solutions":["Retry the request; if reproducible, reduce prompt/output size","Inspect provider/proxy logs for upstream disconnects or content-filter aborts","Check LiteLLM proxy version and logs if streaming through it","Use the partial accumulated result as a degraded response when acceptable","Bypass intermediaries (proxy/LB) to confirm whether the provider or the hop is closing the stream"],"exampleFix":"// before\nresult, err := call()\n// after: handle premature EOF gracefully\nresult, err := call()\nif err != nil && strings.Contains(err.Error(), \"model stream ended unexpectedly\") {\n    if len(result.Content) > 0 { /* accept partial content */ } else { result, err = call() }\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isPrematureEOF(err error) bool { return err != nil && strings.Contains(err.Error(), \"model stream ended unexpectedly\") }","tryCatchPattern":"result, err := call()\nif isPrematureEOF(err) {\n    if partialContentUsable(result) { return result, nil }\n    return retryOrFallbackModel()\n}","preventionTips":["Keep intermediaries (LiteLLM, LBs) configured with generous stream idle timeouts","Cap prompt/output sizes so providers are less likely to abort mid-stream","Use the accumulator's partial result as a degraded-mode answer","Track premature-EOF rates per provider to detect upstream instability"],"tags":["streaming","eof","llm","connection-drop"],"backgroundTag":"stream-ended-unexpectedly","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"}