mastra-ai/mastra · error · Error
Cannot start an overlapping WebSocket Responses continuation
Error message
Cannot start an overlapping WebSocket Responses continuation. Wait for the active stream to finish before sending previous_response_id.
What it means
The OpenAI WebSocket Responses transport maintains a connection-local previous_response_id cache and supports only one active stream at a time. If a new request arrives while a stream is busy AND it carries a previous_response_id (a continuation depending on socket-local state), the library throws this Error instead of silently corrupting the conversation. Requests without previous_response_id are safely fallen back to HTTP fetch.
Source
Thrown at packages/core/src/llm/model/openai-websocket-fetch.ts:181
}
let body: Record<string, unknown>;
try {
body = JSON.parse(typeof init.body === 'string' ? init.body : '');
} catch {
return globalThis.fetch(input, init);
}
if (!body.stream) {
return globalThis.fetch(input, init);
}
// Prevent concurrent streams from sharing one WebSocket transport instance.
// Only fall back to HTTP when the request does not depend on the socket's
// connection-local previous_response_id cache.
if (busy) {
if (body.previous_response_id) {
throw new Error(
'Cannot start an overlapping WebSocket Responses continuation. Wait for the active stream to finish before sending previous_response_id.',
);
}
return globalThis.fetch(input, init);
}
const headers = normalizeHeaders(init.headers);
const authorization =
headers['authorization'] ?? (options?.apiKeyAsBearer && headers['api-key'] ? `Bearer ${headers['api-key']}` : '');
// Acquire the busy lock before awaiting to prevent races
busy = true;
let connection: WebSocket;
try {
connection = await getConnection(authorization, headers, init?.signal);
} catch (err) {
busy = false;
throw err;View on GitHub (pinned to 75dd419e61)
Solutions
- Await the active stream's completion before sending a request with previous_response_id
- Serialize requests through a queue/mutex per WebSocket transport instance
- Use separate transport instances for concurrent conversations
- Drop previous_response_id if the continuation doesn't require socket-local state (it will fall back to HTTP)
Example fix
// before
streamOne.start(); // not awaited
conn.websocketFetch({ previous_response_id: 'resp_1', ... }); // throws
// after
await streamOne.finished;
await conn.websocketFetch({ previous_response_id: 'resp_1', ... }); Defensive patterns
Strategy: fallback
Validate before calling
// Guard before sending a continuation
if (conn.isBusy && body.previous_response_id) {
throw new Error('Active stream in progress; defer the continuation');
} Try / catch
let res;
try {
res = await conn.websocketFetch({ ...body, previous_response_id: lastId });
} catch (e) {
if (e.message.includes('overlapping WebSocket Responses continuation')) {
await activeStream.finished; // wait, then retry the continuation
res = await conn.websocketFetch({ ...body, previous_response_id: lastId });
} else {
throw e;
}
} Prevention
- Always await stream completion before sending follow-up turns with previous_response_id
- Wrap each WebSocket transport in a request queue so calls are serialized
- Give concurrent conversations their own transport instances
- Track stream state (busy/idle) in your agent orchestration layer
When it happens
Trigger: Calling websocketFetch for a Responses continuation (body.previous_response_id set) while another stream is still active on the same WebSocket transport instance.
Common situations: Sending a follow-up message before the previous streamed response finished; concurrent agent turns sharing one client; fire-and-forget stream calls not awaited before issuing the next turn.
Related errors
- Cannot register run ${output.runId}: thread is already activ
- OpenAISDKAgent resumeData must include a message.
- OpenAISDKAgent resumeData must include previousResponseId, c
- UI Messages require a data property when using data- prefixe
- UI Messages require a data property when using data- prefixe
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/a579da59f5bca74e.
Report an issue: GitHub.