Stream Decoder Buffer Limits#
Status (as of 2026-10-03): Buffer limits are proposed in PR #8737 (open, not yet merged). The current main branch has no configurable memory bounds on either decoder.
Current behavior (no limits)#
LineDecoderStream accumulates incoming text into a single buffer string until a \n, \r, or \r\n delimiter is found . There is no maximum length check; a line that never terminates grows without bound. On stream end, an unterminated buffer throws an error — this is a correctness guard, not a size limit .
SSEEventDecoder accumulates unfinished line fragments in lineChunks: string[] and completed data: field values in dataLines: string[] . The only constructor option is trailing: "drop" | "dispatch", which controls whether data remaining at stream end is discarded or emitted as a final event . Neither array has a size cap.
Risk: A peer that continuously streams without sending a newline or SSE frame boundary can grow process memory until exhaustion. This is the root cause described in PR #8737.
Proposed limits (PR #8737)#
PR #8737 — "fix(streaming): bound decoder buffers without blocking large payloads" — adds configurable, default-bounded limits at multiple layers:
| Option | Default | Scope |
|---|---|---|
maxLineLength | 16 MiB | LineDecoderStream, SSEEventDecoder, forwarded through AssistantTransportDecoder and DataStreamDecoder |
maxEventLength | 16 MiB | SSEEventDecoder (counts joined data: lines including separator newlines) |
maxStreamLineLength | 16 MiB | useAssistantTransportRuntime, useDataStreamRuntime (React runtime options) |
maxStreamEventLength | 16 MiB | useAssistantTransportRuntime (React runtime options) |
The limits are additive — callers that need to transport payloads larger than 16 MiB can raise them explicitly without changing default behavior . Exceeding a limit rejects decoding with a specific line-length or event-length error and discards the rejected frame .
The PR modifies these files across the decoder stack:
packages/assistant-stream/src/core/utils/stream/LineDecoderStream.tspackages/assistant-stream/src/core/utils/stream/SSEEventDecoder.tspackages/assistant-stream/src/core/serialization/assistant-transport/AssistantTransport.tspackages/assistant-stream/src/core/serialization/data-stream/DataStream.tspackages/assistant-stream/src/core/serialization/ui-message-stream/UIMessageStream.tspackages/core/src/react/runtimes/assistant-transport/useAssistantTransportRuntime.tspackages/react-data-stream/src/useDataStreamRuntime.ts
Related: incremental SSE fragmentation fix (PR #7262, merged)#
PR #7262 — "fix(assistant-stream): scan fragmented SSE lines incrementally" — is a merged performance fix that replaced the old lineBuffer string accumulation in SSEEventDecoder with the current lineChunks: string[] approach . This eliminated quadratic scanning when large events arrive in many small chunks (e.g., a 1 MiB payload in 1 KiB chunks dropped from ~112 ms to ~0.33 ms) . This change is not a memory cap — it is an efficiency improvement that happens to change how the buffer is stored.
Where to look#
| File | Purpose |
|---|---|
LineDecoderStream.ts | Core line decoder; buffer is this.buffer (string) |
SSEEventDecoder.ts | SSE frame decoder; fragments in lineChunks, data in dataLines |
| PR #8737 | Proposed buffer limit implementation and API surface |
| PR #7262 | Merged incremental fragmentation fix (context for lineChunks design) |