vercel/ai · error
Failed to reconnect after ${this.maxConsecutiveErrors} conse
Error message
Failed to reconnect after ${this.maxConsecutiveErrors} consecutive errors. Last error: ${getErrorMessage(error)} What it means
During reconnection the transport retries the GET stream request, incrementing a consecutive-error counter each time parsing/connection fails. If it fails maxConsecutiveErrors times in a row, it throws with the count and the last underlying error message. This is a give-up guard against infinite reconnect loops.
Source
Thrown at packages/workflow/src/workflow-chat-transport.ts:520
chunkIndex++;
if (orphanFilter?.shouldDrop(chunk.value)) continue;
yield chunk.value;
if (chunk.value.type === 'finish') {
gotFinish = true;
}
}
// Reset consecutive error count only after successful stream parsing
consecutiveErrors = 0;
} catch (error) {
console.error('Error in chat GET reconnectToStream', error);
consecutiveErrors++;
if (consecutiveErrors >= this.maxConsecutiveErrors) {
throw new Error(
`Failed to reconnect after ${this.maxConsecutiveErrors} consecutive errors. Last error: ${getErrorMessage(error)}`,
);
}
}
}
await this.onFinish(gotFinish, { chatId: options.chatId, chunkIndex });
}
private async onFinish(
gotFinish: boolean,
{ chatId, chunkIndex }: { chatId: string; chunkIndex: number },
) {
if (gotFinish) {
await this.onChatEnd?.({ chatId, chunkIndex });
} else {
throw new Error('No finish chunk received');
}View on GitHub (pinned to 69428b1f8b)
Solutions
- Inspect 'Last error' in the message to find the root cause (parse error vs network).
- Raise maxConsecutiveErrors or add backoff if the network is merely flaky.
- Fix server-side chunk emission so chunks conform to the UI message chunk schema.
- Add application-level retry with delay around reconnectToStream.
Example fix
// before
new WorkflowChatTransport({ maxConsecutiveErrors: 3 })
// after
new WorkflowChatTransport({ maxConsecutiveErrors: 10 }) Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: ensure reconnect endpoint healthy
const probe = await fetch(reconnectUrl + '?startIndex=0', { headers: authHeaders });
if (!probe.ok) await waitForServer(); Try / catch
try {
await transport.reconnectToStream({ chatId });
} catch (e) {
if (e instanceof Error && e.message.includes('consecutive errors')) {
await new Promise(r => setTimeout(r, backoffMs));
await transport.reconnectToStream({ chatId }); // outer retry with backoff
} else throw e;
} Prevention
- Configure maxConsecutiveErrors generously for flaky networks.
- Log the inner 'Last error' to distinguish parse errors from network errors.
- Ensure server chunk format matches the UI message chunk schema version.
- Add exponential backoff at the application layer around reconnects.
When it happens
Trigger: Persistent stream failures during reconnectToStream: repeated malformed chunks (schema parse errors thrown from parseJsonEventStream), repeated network drops, or a server that keeps erroring — reaching maxConsecutiveErrors consecutive failures.
Common situations: Server emitting chunks that fail uiMessageChunkSchema validation; unstable network/proxy dropping connections; server 500-loop on the reconnect endpoint; maxConsecutiveErrors set too low for flaky networks.
Related errors
- The response body is empty.
- Failed to fetch chat: ${response.status} ${await response.te
- Cannot connect to API: ${cause.message}
- Failed after ${tryNumber} attempts. Last error: ${errorMessa
- Failed after ${tryNumber} attempts with non-retryable error:
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/490e2fd29fee5d7e.
Report an issue: GitHub.