See it live
Same stream. One breaks, one doesn't.
A model streams JSON token by token, invalid for most of its life. Left: piped straight into JSON.parse(). Right: through the validator. This demo runs the actual npm package.
component failed to render
Without it, the UI is unusable until the final token lands. With it, every frame is valid, so it renders progressively.
The challenge
Streaming LLM output is a stream of broken JSON. Standard parsers throw on anything incomplete, so apps either buffer the whole response (killing the point of streaming) or write brittle ad-hoc string patching. It needed to be correct across quote types, resilient to partial structures, stateful across chunks, and light enough to drop into any project.
The approach
I built an append-aware parser that tracks structural state between chunks and completes the JSON on demand, balancing quotes and brackets, closing open containers, and filling incomplete properties with configurable placeholder values. It ships as a TypeScript-first, zero-dependency package with a simple one-shot API and a stateful streaming parser, backed by 95%+ test coverage.
Drop-in usage
npm install llm-json-validator
import { validateStreamingJson } from "llm-json-validator";
// a half-streamed chunk from the model
const partial = '{"title":"Weekly Rep';
validateStreamingJson(partial, { returnParsedJson: true });
// → { title: "Weekly Rep" } ✓ always validWhat makes it work
Append-aware streaming
A stateful parser accepts chunks as they arrive and returns valid JSON (string or parsed object) at every step.
Quote & bracket healing
Balances unmatched single/double quotes and auto-closes open brackets, with configurable dummy values for incomplete fields.
Zero-dep & typed
Fully typed, self-contained, and lightweight, 95%+ test coverage and backward compatible across the 1.x line.
- 0
- dependencies
- 95%+
- test coverage
- MIT
- open source