vercel/ai · critical
OpenCode prompt failed: ${formatError(prompted.error)}
Error message
OpenCode prompt failed: ${formatError(prompted.error)} What it means
runPrompt sends the user prompt to the OpenCode session with legacySessionPrompt. If the prompt API returns an error result, the bridge aborts the event stream, closes the user-message queue with this error, and throws it. The turn fails immediately with the OpenCode server's formatted error message.
Source
Thrown at packages/harness-opencode/src/bridge/index.ts:769
message.accept();
} catch (error) {
message.reject(error);
} finally {
submittingUserMessage = false;
}
}
})();
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);View on GitHub (pinned to 69428b1f8b)
Solutions
- Inspect formatError output in the message for the server-side cause (invalid model, busy session, etc.).
- Verify the session id is still valid and no other prompt is in flight for it.
- Check the model/provider configured in start options exists on the OpenCode server.
- Retry the turn if the failure was transient (e.g. 502 from the underlying LLM provider).
Example fix
// before: stale session id reused across restarts
await bridge.runTurn({ sessionId: oldId, prompt }); // OpenCode prompt failed: session not found
// after: let the bridge create a fresh session
await bridge.runTurn({ prompt }); // new session created automatically Defensive patterns
Strategy: try-catch
Validate before calling
const session = await fetch(`${base}/session/${sessionId}`).then(r => r.ok);
if (!session) throw new Error(`Session ${sessionId} does not exist before prompting`); Type guard
function isPromptError(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith('OpenCode prompt failed:');
} Try / catch
try {
await bridge.runTurn({ sessionId, prompt });
} catch (e) {
if (isPromptError(e)) {
console.error('Prompt error detail:', e.message.replace('OpenCode prompt failed: ', ''));
// recreate session or fix model config, then retry
} else throw e;
} Prevention
- Never reuse session ids across OpenCode server restarts.
- Serialize prompts per session — no concurrent turns.
- Validate model/provider options before submitting.
- Retry turns on transient 5xx with backoff.
When it happens
Trigger: Calling a turn (runTurn -> runPrompt) when legacySessionPrompt resolves prompted.error — server rejected the prompt request (invalid session id, session already busy, provider/model misconfigured, HTTP 4xx/5xx from OpenCode).
Common situations: Prompting a stale/deleted session id; a model/provider name not configured on the OpenCode server; concurrent prompts to the same session; OpenCode server returning 409/500 while processing.
Related errors
- OpenCode session create failed: ${formatError(created.error)
- OpenCode compaction failed: ${formatError(compacted.error)}
- Failed to fetch the response.
- The response body is empty.
- ${readErrorMessage({ value, status: response.status })}
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/7d44da9c7b825ce3.
Report an issue: GitHub.