{"record":{"id":"490e2fd29fee5d7e","repo":"vercel/ai","slug":"failed-to-reconnect-after-this-maxconsecutiveerr","errorCode":null,"errorMessage":"Failed to reconnect after ${this.maxConsecutiveErrors} consecutive errors. Last error: ${getErrorMessage(error)}","messagePattern":"Failed to reconnect after (.+?) consecutive errors\\. Last error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/workflow/src/workflow-chat-transport.ts","lineNumber":520,"sourceCode":"\n          chunkIndex++;\n\n          if (orphanFilter?.shouldDrop(chunk.value)) continue;\n\n          yield chunk.value;\n\n          if (chunk.value.type === 'finish') {\n            gotFinish = true;\n          }\n        }\n        // Reset consecutive error count only after successful stream parsing\n        consecutiveErrors = 0;\n      } catch (error) {\n        console.error('Error in chat GET reconnectToStream', error);\n        consecutiveErrors++;\n\n        if (consecutiveErrors >= this.maxConsecutiveErrors) {\n          throw new Error(\n            `Failed to reconnect after ${this.maxConsecutiveErrors} consecutive errors. Last error: ${getErrorMessage(error)}`,\n          );\n        }\n      }\n    }\n\n    await this.onFinish(gotFinish, { chatId: options.chatId, chunkIndex });\n  }\n\n  private async onFinish(\n    gotFinish: boolean,\n    { chatId, chunkIndex }: { chatId: string; chunkIndex: number },\n  ) {\n    if (gotFinish) {\n      await this.onChatEnd?.({ chatId, chunkIndex });\n    } else {\n      throw new Error('No finish chunk received');\n    }","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/workflow/src/workflow-chat-transport.ts#L502-L538","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew WorkflowChatTransport({ maxConsecutiveErrors: 3 })\n// after\nnew WorkflowChatTransport({ maxConsecutiveErrors: 10 })","handlingStrategy":"retry","validationCode":"// pre-flight: ensure reconnect endpoint healthy\nconst probe = await fetch(reconnectUrl + '?startIndex=0', { headers: authHeaders });\nif (!probe.ok) await waitForServer();","typeGuard":null,"tryCatchPattern":"try {\n  await transport.reconnectToStream({ chatId });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('consecutive errors')) {\n    await new Promise(r => setTimeout(r, backoffMs));\n    await transport.reconnectToStream({ chatId }); // outer retry with backoff\n  } else throw e;\n}","preventionTips":["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."],"tags":["network","retry","reconnect","transport"],"backgroundTag":"stream-reconnect-failed","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}