lesson depth
Mastery
not started · 0%

Partial JSON Parsing for Streams

How to read, validate, and extract nested values from incomplete JSON streams using specialized chunk-aware parsers.

Freshness: current12 min readAI User Experience and Human-AI Interaction

Mental model

Standard JSON.parse() is all-or-nothing: if you omit even a single closing brace, it throws a syntax error. When a model outputs JSON tokens incrementally (e.g. {"status": "pending", "data": {"percentage": 42), standard parsers fail. Partial JSON parsing acts as a repair worker: it temporarily appends closing brackets, quotes, and braces to the end of the text to synthesize a valid JSON string at any point in the stream.

Receive incomplete JSON token
Scan token structure for open elements
Auto-append missing braces or quotes
Synthesize valid string
JSON.parse and update UI
Conceptual teaching model synthesized from:JSON parser for incomplete streams - AI SDK UIVercel AI SDK Core - Stream Helpers

Theory

When streaming structured tool arguments, the model outputs JSON incrementally:

text(3 lines)
1Chunk 1: {"user": {"name": "
2Chunk 2: {"user": {"name": "John", "age": 3

To render the name "John" to the UI before the generator finishes, we must parse the partial string. A custom parser tracks the state of open delimiters:

  1. Unclosed Strings: If a string literal is open (uneven quotes "), append a closing quote " to the end.
  2. Open Objects: Track open braces { and append matching closing braces } in reverse order.
  3. Open Arrays: Track open brackets [ and append matching closing brackets ].

Here is a simplified state-based repair logic block:

typescript(43 lines)
1function parsePartialJSON(jsonString: string): any {
2 // If clean, parse normally
3 try {
4 return JSON.parse(jsonString);
5 } catch {
6 // Repair step
7 let repaired = jsonString.trim();
8
9 // 1. Repair unclosed string literals
10 const doubleQuoteCount = (repaired.match(/"/g) || []).length;
11 const isInsideString = doubleQuoteCount % 2 === 1;
12 if (isInsideString) {
13 repaired += '"';
14 }
15
16 // 2. Scan and close containers
17 const openBrackets: string[] = [];
18 for (let i = 0; i < repaired.length; i++) {
19 const char = repaired[i];
20 // Skip escaped quotes
21 if (char === '"' && repaired[i - 1] !== '\\') {
22 // Toggle string state block
23 }
24 // If we are not inside a string, trace brackets
25 if (char === '{') openBrackets.push('}');
26 else if (char === '[') openBrackets.push(']');
27 else if (char === '}') openBrackets.pop();
28 else if (char === ']') openBrackets.pop();
29 }
30
31 // Append closing brackets in reverse order
32 while (openBrackets.length > 0) {
33 repaired += openBrackets.pop();
34 }
35
36 try {
37 return JSON.parse(repaired);
38 } catch {
39 return null; // Parse failed
40 }
41 }
42}
23 lines hidden

Alternatives and trade-offs

  • Manual Regex extraction: Using regex templates (e.g. "name":\s*"([^"]*)") to pull properties. Very fast, but breaks down if keys are nested or have identical names.
  • Auto-Repair Parser: Restructuring incomplete strings on the fly. Works with nested arrays and objects, but requires additional CPU time to scan and repair strings on every chunk.
  • Server-Side Chunk Buffering: Buffering full JSON structures on the server and only streaming complete property keys. Minimizes client complexity, but delays the initial Time-to-First-Token rendering of nested structures.

Failure modes and misconceptions

  • Swallowing Numeric values: If a number value is truncated (e.g., "age": 3), parsing the repaired string immediately gives 3. If the next chunk yields 0 (making it 30), the client UI will show a rapid jump from 3 to 30. Account for active cursors in numeric fields.
  • Malformed Escape Characters: If a chunk terminates right after a backslash (\), appending a quote immediately creates an escaped quote (\"), causing the repair step to fail. Strip trailing backslashes before running repairs.

Knowledge check

Reflect before revealing the guide

What characters must be tracked to safely repair an incomplete JSON stream?

Decision scenario

When developing a wizard that displays a structured list of recommendations as they stream from a model, do not wait for the generation to finish. Use a partial JSON parser (like Vercel AI SDK's built-in chunk-aware parser) to read the array incrementally and render item cards on the screen as soon as their nested fields validate.

Learning outcomes

  • Explain Partial JSON Parsing for Streams as a system mechanism rather than a slogan.
  • Compare its alternatives, trade-offs, and production failure modes.
  • Apply the concept to a decision and identify evidence that would validate it.

Trade-offs

Using Partial JSON Parsing for Streams can improve capability or control, but it also introduces cost, latency, complexity, and failure modes that must be measured against an explicit objective.

Prerequisites & Related Concepts (2)

Private notes

0 words
Next