can1357/oh-my-pi · error · AnthropicStreamEnvelopeError

stream ended before message_start

Error message

stream ended before message_start

What it means

This AnthropicStreamEnvelopeError is thrown when the SSE stream terminates without delivering the mandatory `message_start` event (and often no events at all). The library cannot attribute or finalize a message it never saw begin, so it fails the turn; this error is transparently retried before replay-unsafe content streams.

Source

Thrown at packages/ai/src/providers/anthropic.ts:2662

								}
							}
						} else if (event.type === "message_stop") {
							sawTerminalEnvelope = true;
							sawMessageStop = true;
							// The protocol is complete even if a broken keep-alive leaves the HTTP body open.
							break;
						}
					}

					const firstEventTimeoutError = activeAbortTracker.getLocalAbortReason();
					if (firstEventTimeoutError) {
						throw firstEventTimeoutError;
					}
					if (activeAbortTracker.wasCallerAbort()) {
						throw new AIError.AbortError();
					}
					if (!sawEvent || !sawMessageStart) {
						throw new AIError.AnthropicStreamEnvelopeError("stream ended before message_start");
					}
					if (!sawTerminalEnvelope) {
						// Neither a message_delta stop_reason nor message_stop arrived: the
						// connection died mid-generation. Finalizing the partial message as
						// a clean "stop" would make the agent loop treat the truncated turn
						// as complete (silent mid-sentence halt), so fail the turn. The
						// envelope error is transparently retried before replay-unsafe
						// content streams; afterwards it surfaces as an error turn whose
						// complete tool calls the agent loop salvages
						// (`recoverTransientErrorToolTurn` recognizes the envelope-error
						// text and `retainCompletedToolCalls` drops half-streamed calls).
						throw new AIError.AnthropicStreamEnvelopeError("stream ended before message_stop");
					}
					if (!sawMessageStop) {
						// A stop_reason arrived via message_delta, so generation finished;
						// only the trailing message_stop frame is missing (non-conforming
						// gateway). Degrade to best-effort instead of discarding the turn.
						reportAnthropicEnvelopeAnomaly("stream ended before message_stop");

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry the request — the library retries envelope errors transparently when replay is safe; enable/configure retries.
  2. Check network path (VPN, proxy, LB idle timeouts) for premature connection termination of SSE streams.
  3. Verify the gateway supports streaming (no buffering, correct content-type text/event-stream) and forwards Anthropic error frames.
  4. Increase first-event timeouts and check Anthropic status for overload incidents.
Defensive patterns

Strategy: retry

Validate before calling

// Precheck that the endpoint streams and stays alive:
const res = await fetch(endpoint, { method: "POST", headers, signal, body });
if (!res.ok || !res.headers.get("content-type")?.includes("text/event-stream")) {
  throw new Error(`Expected SSE 200, got ${res.status} ${res.headers.get("content-type")}`);
}

Try / catch

try {
  yield* streamAnthropicEvents(request);
} catch (err) {
  if (err instanceof AIError.AnthropicStreamEnvelopeError && /ended before message_start/.test(err.message)) {
    // transient: retry with backoff (library retries automatically when replay-safe)
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: The response body ends (connection close, gateway drop, immediate 200-with-empty-stream) before any message_start frame, with no local first-event timeout error and no caller abort — checked right after the SSE loop in iterateAnthropicEvents.

Common situations: Flaky networks or load balancers closing idle connections; proxies buffering SSE and cutting the stream; Anthropic 529/overload responses funneled into a dead stream; server-side timeout before first token; misconfigured gateways that accept the request but emit nothing.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/388a863f137edf52. Report an issue: GitHub.