vercel/ai · error
OpenCode event stream ended before the turn settled.
Error message
OpenCode event stream ended before the turn settled.
What it means
runPrompt listens to the OpenCode SSE event stream and waits on a deferred that resolves when the turn settles (idle/busy transition, error, or structured output). If the event stream itself ends first, the deferred resolves with 'stream-ended' and this error is thrown. It means the server closed the event connection before reporting any turn completion.
Source
Thrown at packages/harness-opencode/src/bridge/index.ts:776
})();
const prompted = await legacySessionPrompt({
client,
sessionId,
start,
});
if (prompted.error) {
eventsAbort.abort();
turn.experimental_userMessages.close(
new Error(`OpenCode prompt failed: ${formatError(prompted.error)}`),
);
throw new Error(`OpenCode prompt failed: ${formatError(prompted.error)}`);
}
const settlement = await turnSettled.promise;
eventsAbort.abort();
await eventLoop.catch(() => {});
await userMessageLoop.catch(() => {});
if (settlement === 'stream-ended') {
throw new Error('OpenCode event stream ended before the turn settled.');
}
if (terminalError) throw new Error(terminalError);
if (!sawFinishStep) {
const emittedFallback = await emitContextFallback({
client,
sessionId,
assistantBaseline,
state,
emit,
emitContent: !sawContent,
}).catch(() => false);
if (!emittedFallback) {
throw new Error(
'OpenCode turn settled without a correlated assistant response.',
);
}
}
const finalSessionTokens =View on GitHub (pinned to 69428b1f8b)
Solutions
- Increase proxy idle/read timeouts for the OpenCode event endpoint (e.g. nginx proxy_read_timeout).
- Check OpenCode server logs for a crash or restart during the turn.
- Retry the turn; transient network drops are the most common cause.
- Run the bridge and server on the same host/network to rule out intermediary connection termination.
Example fix
// before: nginx default 60s read timeout kills long SSE turns
location /event { proxy_pass http://opencode; }
// after
location /event { proxy_pass http://opencode; proxy_read_timeout 3600s; proxy_buffering off; } Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
function isStreamEndedError(e: unknown): e is Error {
return e instanceof Error && e.message === 'OpenCode event stream ended before the turn settled.';
} Try / catch
try {
await bridge.runTurn(...);
} catch (e) {
if (isStreamEndedError(e) && attempt < 3) {
await sleep(2 ** attempt * 1000);
return runTurnWithRetry(attempt + 1);
}
throw e;
} Prevention
- Disable proxy buffering and raise read timeouts for SSE endpoints.
- Keep the OpenCode server supervised to avoid mid-turn crashes.
- Avoid running long turns over flaky networks/VPN.
- Add automatic retry with backoff for this specific error.
When it happens
Trigger: The OpenCode SSE connection drops or the server closes it mid-turn (network interruption, server restart, idle timeout, proxy buffering/terminating long-lived connections), before a busy->idle transition or error event arrives.
Common situations: Reverse proxies (nginx default proxy_read_timeout) cutting long streaming requests; OpenCode server crash during a long tool loop; laptop sleep/network switch dropping the connection.
Related errors
- The response body is empty.
- Incomplete Amazon Bedrock event-stream frame: ${buffer.lengt
- The response body is empty.
- MCP SSE Transport Error: Connection closed unexpectedly
- 'element streams in no-schema mode' functionality not suppor
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/25e31c1d380c042d.
Report an issue: GitHub.