vercel/ai · warning
[WorkflowChatTransport] Dropping orphan UI chunk (${orphanKi
Error message
[WorkflowChatTransport] Dropping orphan UI chunk (${orphanKind} for id "${orphanRef}") on resume — the resume position landed mid-part. The dropped chunk(s) reference a part whose start chunk wasn't in the resumed window. To preserve the full message, configure your stream endpoint to rewind to a step boundary before returning the readable. See: https://workflow.dev/docs/ai/resumable-streams#mid-part-resumes What it means
When resuming a UI message stream, chunks can reference a message part whose start chunk was not included in the resumed window (an 'orphan' chunk). The transport drops such chunks so the UI isn't corrupted, and warns once (first occurrence only) that the resume landed mid-part, with a doc link on how to avoid it.
Source
Thrown at packages/workflow/src/workflow-chat-transport.ts:48
* part from those directly), so all three mark the call id as seen.
*
* This is a best-effort safety net — it preserves only the parts that the
* resumed window includes a `*-start` for. Server-side rewinding to a step
* boundary is the proper fix when you want the full message preserved.
*/
type OrphanFilter = {
shouldDrop: (chunk: UIMessageChunk) => boolean;
};
function createOrphanFilter(): OrphanFilter {
const seenStartedIds = new Set<string>();
const seenStartedToolCallIds = new Set<string>();
let warnedOnce = false;
function warnOnce(orphanKind: string, orphanRef: string) {
if (warnedOnce) return;
warnedOnce = true;
console.warn(
'[WorkflowChatTransport] Dropping orphan UI chunk ' +
`(${orphanKind} for id "${orphanRef}") on resume — ` +
'the resume position landed mid-part. The dropped chunk(s) ' +
"reference a part whose start chunk wasn't in the resumed " +
'window. To preserve the full message, configure your ' +
'stream endpoint to rewind to a step boundary before ' +
'returning the readable. See: ' +
'https://workflow.dev/docs/ai/resumable-streams#mid-part-resumes',
);
}
function shouldDrop(chunk: UIMessageChunk): boolean {
switch (chunk.type) {
case 'reset-step':
seenStartedIds.clear();
seenStartedToolCallIds.clear();
return false;
case 'text-start':View on GitHub (pinned to 69428b1f8b)
Solutions
- Configure the stream endpoint to rewind to a step boundary before returning the readable, so a part-start chunk always begins the resumed window.
- Include the part-start chunks in the resumed stream window (start the stream earlier).
- Persist the full stream server-side and replay from the last complete step boundary.
- Accept the drop if losing the partially-started part is acceptable.
Defensive patterns
Strategy: fallback
Prevention
- Resume streams from step boundaries, never mid-part
- Persist full stream logs server-side for replay
- Test disconnect/reconnect mid-stream scenarios against your endpoint
When it happens
Trigger: Calling reconnectToStream / resuming a chat where the server's reconnection endpoint returns a stream whose first chunks are continuation chunks (e.g. text-delta, tool-output updates) without the preceding part-start chunk (e.g. text-start, tool-input-start) for the same id.
Common situations: Custom stream endpoints that resume from an arbitrary chunk index rather than a step boundary; servers trimming persisted stream logs; clients reconnecting after a mid-part disconnect.
Related errors
- [WorkflowChatTransport] Negative initialStartIndex is config
- No finish chunk received
- [WorkflowAgent] Provider-executed tool "${toolCall.toolName}
- 'element streams in no-schema mode' functionality not suppor
- 'element streams in object mode' functionality not supported
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/d675409e84fcedac.
Report an issue: GitHub.