vercel/ai · critical
${terminalError}
Error message
${terminalError} What it means
When the OpenCode event stream emits a session.error event, runPrompt records the formatted error in terminalError and rethrows it as a plain Error after the turn settles. This is the OpenCode server reporting a terminal failure for the turn (e.g. the underlying model/provider errored). The message is whatever OpenCode reported.
Source
Thrown at packages/harness-opencode/src/bridge/index.ts:778
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 =
(await readSessionTokens({ client, sessionId }).catch(() => undefined)) ??
latestSessionTokens;View on GitHub (pinned to 69428b1f8b)
Solutions
- Read terminalError content in the message — it contains OpenCode's formatted provider/server error — and fix that underlying cause.
- Verify the LLM provider API keys and quotas configured on the OpenCode server.
- Check the model id in your start options is valid for the provider.
- Retry the turn after resolving provider-side issues.
Example fix
// before: expired provider key on opencode server export ANTHROPIC_API_KEY=sk-expired // after export ANTHROPIC_API_KEY=sk-valid opencode auth login
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight provider auth on the OpenCode server
const models = await fetch(`${base}/config/provider`).then(r => r.json());
if (!models?.length) throw new Error('No provider configured on OpenCode server'); Type guard
function isTerminalSessionError(e: unknown): e is Error {
return e instanceof Error && !e.message.startsWith('OpenCode ') && e.message.length > 0 && /error|failed|quota|limit/i.test(e.message);
} Try / catch
try {
await bridge.runTurn(...);
} catch (e) {
if (e instanceof Error && /quota|rate.?limit/i.test(e.message)) {
await sleep(60_000); // back off provider rate limits
} else if (e instanceof Error && /api.?key|auth/i.test(e.message)) {
console.error('Fix provider credentials on the OpenCode server');
} else throw e;
} Prevention
- Validate provider API keys and quotas before long agent runs.
- Use valid model ids for the configured provider.
- Monitor provider status pages during critical runs.
- Set retry/backoff policies for rate-limit errors.
When it happens
Trigger: During a turn, consumeEvents receives event.type === 'session.error' (or terminal failure from the server), e.g. the LLM provider returned an error, the model quota was exhausted, or a tool execution caused a fatal server error.
Common situations: Invalid or rate-limited LLM provider API key on the OpenCode server; provider outage mid-turn; model id not available for the configured provider; OpenCode internal error while executing tools.
Related errors
- statusResult.error
- Transcription failed: ${transcript.error ?? 'Unknown error'}
- Fireworks image generation failed with status: ${status}
- OpenCode session create failed: ${formatError(created.error)
- OpenCode session create returned no id.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/0d70e96d453a55c9.
Report an issue: GitHub.