stablyai/orca · error · NdjsonLineTooLongError
NDJSON line exceeds max ${maxLineBytes} bytes (${lineBytes}
Error message
NDJSON line exceeds max ${maxLineBytes} bytes (${lineBytes} bytes encoded) What it means
NdjsonLineTooLongError: encodeNdjson throws when the JSON-serialized message exceeds the byte limit (default 16 MB, NDJSON_MAX_LINE_BYTES). This is a hard backstop so a daemon socket peer that never sends a newline — or a single oversized frame — cannot grow the parser buffer without bound. The error carries the actual and maximum byte counts.
Source
Thrown at src/main/daemon/ndjson.ts:17
export const NDJSON_MAX_LINE_BYTES = 16 * 1024 * 1024
export class NdjsonLineTooLongError extends Error {
constructor(
readonly lineBytes: number,
readonly maxLineBytes: number
) {
super(`NDJSON line exceeds max ${maxLineBytes} bytes (${lineBytes} bytes encoded)`)
this.name = 'NdjsonLineTooLongError'
}
}
export function encodeNdjson(msg: unknown, maxLineBytes = NDJSON_MAX_LINE_BYTES): string {
const line = JSON.stringify(msg)
const lineBytes = Buffer.byteLength(line, 'utf8')
if (lineBytes > maxLineBytes) {
throw new NdjsonLineTooLongError(lineBytes, maxLineBytes)
}
return `${line}\n`
}
export type NdjsonParser = {
feed(chunk: string): void
reset(): void
}
export type NdjsonParserOptions = {
maxLineBytes?: number
}
export function createNdjsonParser(
onMessage: (msg: unknown) => void,
onError?: (err: Error) => void,
options: NdjsonParserOptions = {}
): NdjsonParser {View on GitHub (pinned to 1136503c6a)
Solutions
- Chunk the large payload into multiple smaller NDJSON messages (e.g., the history seed transfer protocol) instead of one frame.
- Raise maxLineBytes deliberately only if you control both peers and understand the memory cost.
- Strip/avoid embedding large binary blobs inline; reference them by transfer id instead.
- On the parser side, handle the onError callback to surface the oversized-line condition rather than silently dropping data.
Example fix
// before: one giant frame
encodeNdjson({ scrollback: hugeBase64 })
// after: chunked transfer
const metrics = measureTerminalHistorySeed([hugeBase64])
const id = registry.start(clientId, metrics)
for (const chunk of iterateTerminalHistorySeedChunks([hugeBase64])) {
registry.append(clientId, id, i++, chunk)
} Defensive patterns
Strategy: validation
Validate before calling
import { NDJSON_MAX_LINE_BYTES } from './ndjson'
function fitsNdjson(msg: unknown, max = NDJSON_MAX_LINE_BYTES): boolean {
return Buffer.byteLength(JSON.stringify(msg), 'utf8') <= max
}
if (!fitsNdjson(msg)) { /* chunk the payload instead */ } Type guard
import { NdjsonLineTooLongError } from './ndjson'
function isNdjsonTooLong(e: unknown): boolean {
return e instanceof NdjsonLineTooLongError
} Try / catch
try {
sock.write(encodeNdjson(msg))
} catch (e) {
if (e instanceof NdjsonLineTooLongError) {
// split into chunked transfer messages
sendChunked(sock, msg)
} else { throw e }
} Prevention
- Size-check payloads with Buffer.byteLength before encoding.
- Use the seed-transfer protocol for large scrollback instead of one inline frame.
- Handle the parser's onError so oversized incoming lines are surfaced, not silently dropped.
When it happens
Trigger: encodeNdjson(msg) where Buffer.byteLength(JSON.stringify(msg), 'utf8') exceeds maxLineBytes. The parser path (createNdjsonParser) reports the same message via onError when an incoming line exceeds the limit.
Common situations: Embedding a very large base64 blob, screenshot, or scrollback payload in a single NDJSON frame; a payload that grew past the limit after a format change; a peer streaming an unbounded paste without chunking.
Related errors
- Unexpected helper handshake: ${JSON.stringify(capabilities)}
- invalid relay hello JSON
- expected plaintext relay hello
- unknown tool: {tool}
- provider_incompatible
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/5577bd9207936f8b.
Report an issue: GitHub.