flashman
← All posts

NDJSON stream truncated line debugging

Debug NDJSON streams by preserving line boundaries, handling final records, separating transport chunks, limiting memory, and reporting malformed JSON safely.

2026-09-13 · 6 min read · Rahul Chitturi

  • ndjson
  • json
  • streaming

Newline-delimited JSON places one complete JSON value on each line. A network or file read can split anywhere, including inside a UTF-8 character or JSON string, so a transport chunk is not a record.

Failures commonly appear only under load when code parses each received chunk independently, drops an incomplete final line, or accepts an oversized record while waiting for a delimiter.

Separate chunks from records

Feed bytes through a streaming text decoder, append decoded text to a bounded carry buffer, and extract complete lines. Keep the unfinished suffix for the next chunk and process it only when more bytes arrive or the stream ends.

  • Define LF versus CRLF handling.
  • Do not split a multibyte UTF-8 sequence.
  • Decide whether blank lines are rejected or ignored.
  • Cap bytes per record before JSON parsing.

Define end-of-stream behavior

State whether the final record requires a newline. If an unterminated final line is accepted, parse it exactly once at clean EOF; if transport ended unexpectedly, preserve the distinction between a valid final record and truncation.

Report record number and a bounded, redacted error location. Do not log complete records that may contain credentials or personal data.

Reproduce with safe Flashman fixtures

Use the JSON formatter on individual synthetic records, diff expected and emitted lines, hash public fixtures for byte identity, and use the units converter to document record limits.

Test one-byte chunks, UTF-8 boundaries, CRLF, blank lines, escaped newlines, malformed middle records, missing final delimiters, cancellation, compressed input, backpressure, and oversized records.

Try these tools