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
- Retry the request — the library retries envelope errors transparently when replay is safe; enable/configure retries.
- Check network path (VPN, proxy, LB idle timeouts) for premature connection termination of SSE streams.
- Verify the gateway supports streaming (no buffering, correct content-type text/event-stream) and forwards Anthropic error frames.
- 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
- Enable/configure retries for envelope errors in agent loops.
- Raise LB/proxy idle timeouts so connections survive time-to-first-token.
- Monitor Anthropic status for overload (529) incidents correlated with these failures.
- Ensure gateways flush SSE immediately (disable buffering/response smoothing).
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
- V2 compaction stream closed before response.completed
- stream ended before message_stop
- SSE stream ended without a resumable event ID
- Perplexity ask stream error: ${message}
- V2 compaction stream parse failed: ${err instanceof Error ?
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/388a863f137edf52.
Report an issue: GitHub.