{"record":{"id":"2ec8bc1dc5bfe63b","repo":"vercel/ai","slug":"received-reasoning-delta-for-missing-reasoning-par","errorCode":null,"errorMessage":"Received reasoning-delta for missing reasoning part with ID \"${chunk.id}\". Ensure a \"reasoning-start\" chunk is sent before any \"reasoning-delta\" chunks.","messagePattern":"Received reasoning-delta for missing reasoning part with ID \"(.+?)\"\\. Ensure a \"reasoning-start\" chunk is sent before any \"reasoning-delta\" chunks\\.","errorType":"exception","errorClass":"UIMessageStreamError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/ui/process-ui-message-stream.ts","lineNumber":505,"sourceCode":"\n            case 'reasoning-start': {\n              const reasoningPart: ReasoningUIPart = {\n                type: 'reasoning',\n                id: chunk.id,\n                text: '',\n                providerMetadata: chunk.providerMetadata,\n                state: 'streaming',\n              };\n              state.activeReasoningParts[chunk.id] = reasoningPart;\n              state.message.parts.push(reasoningPart);\n              write();\n              break;\n            }\n\n            case 'reasoning-delta': {\n              const reasoningPart = state.activeReasoningParts[chunk.id];\n              if (reasoningPart == null) {\n                throw new UIMessageStreamError({\n                  chunkType: 'reasoning-delta',\n                  chunkId: chunk.id,\n                  message:\n                    `Received reasoning-delta for missing reasoning part with ID \"${chunk.id}\". ` +\n                    `Ensure a \"reasoning-start\" chunk is sent before any \"reasoning-delta\" chunks.`,\n                });\n              }\n              reasoningPart.text += chunk.delta;\n              reasoningPart.providerMetadata =\n                chunk.providerMetadata ?? reasoningPart.providerMetadata;\n              write();\n              break;\n            }\n\n            case 'reasoning-end': {\n              const reasoningPart = state.activeReasoningParts[chunk.id];\n              if (reasoningPart == null) {\n                throw new UIMessageStreamError({","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/ai/src/ui/process-ui-message-stream.ts#L487-L523","documentation":"Reasoning parts work like text parts: 'reasoning-start' registers the part in `state.activeReasoningParts` by id. A 'reasoning-delta' whose id has no active reasoning part triggers this UIMessageStreamError. The protocol requires reasoning-start before any deltas.","triggerScenarios":"A UI message stream emits 'reasoning-delta' with an id that never received 'reasoning-start' (or whose part was already closed by 'reasoning-end') — custom writers, resumed streams, or id mismatches.","commonSituations":"Custom provider bridges streaming reasoning without the start chunk; mismatched reasoning part ids between start and delta; replaying a persisted stream from mid-point; streaming libraries upgraded where the id scheme changed.","solutions":["Emit a 'reasoning-start' chunk with the same id before any 'reasoning-delta'.","Confirm reasoning part ids are consistent across start/delta/end.","On resume, re-open the reasoning part with reasoning-start before continuing deltas.","Catch UIMessageStreamError and skip orphan reasoning deltas when processing best-effort streams."],"exampleFix":"// before\nwriter.write({ type: 'reasoning-delta', id: 'r1', delta: 'thinking...' });\n// after\nwriter.write({ type: 'reasoning-start', id: 'r1' });\nwriter.write({ type: 'reasoning-delta', id: 'r1', delta: 'thinking...' });\nwriter.write({ type: 'reasoning-end', id: 'r1' });","handlingStrategy":"validation","validationCode":"const openReasoning = new Set<string>();\nfunction assertReasoningOpen(id: string) {\n  if (!openReasoning.has(id)) throw new Error(`reasoning-delta without reasoning-start for id ${id}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await processUIMessageStream(...);\n} catch (e) {\n  if (e instanceof Error && /reasoning-delta for missing reasoning part/.test(e.message)) {\n    console.warn('Malformed stream: orphan reasoning-delta', e.message);\n  } else throw e;\n}","preventionTips":["Always open reasoning parts with reasoning-start before streaming deltas.","Keep reasoning part ids consistent across start/delta/end.","On resume, re-open reasoning parts before continuing deltas.","Test custom provider bridges with snapshot tests of the chunk sequence."],"tags":["streaming","ui-message-stream","reasoning","protocol-violation"],"backgroundTag":"missing-stream-chunk","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}