Why partial JSON can be a valid object before the closing brace arrives

Streaming a tool call through the Anthropic TypeScript SDK produces a valid JS object on every chunk, even before the closing brace arrives, because the parser seals open structures itself.

1:53 video3 min readWatch on YouTube

If you feed a half-finished JSON string to a standard parser, it throws. That's the expectation almost every developer carries into streaming work, so when the Anthropic TypeScript SDK hands back a usable JavaScript object after every single chunk of a streaming tool call, it looks like it shouldn't be possible. The natural assumption is that a partial value must behave the same way a half-typed string does: broken or empty until the closing brace lands. It doesn't, and the reason why matters for anyone building on streaming tool inputs.

The case that breaks the assumption

Picture a search tool streaming a single argument, the query "solar", across four chunks. Every time a chunk arrives, the SDK's inputJson event fires with a jsonSnapshot. Across those four chunks, the snapshot moves through an empty state, then Q, then Q sol, then Q solar. Each of those four snapshots is already a complete, parsable object, not a fragment that needs to be caught in a try/catch and discarded.

How the parser seals itself shut

The reason comes down to how the SDK's vendored parser is built. It keeps a stack of every object and array it has opened while reading the stream. The instant a chunk ends, mid-value or not, the parser closes each currently open structure with a zero-value default, an empty string where a string was started, an empty object where one was opened, and hands back whatever that produces. It isn't waiting for the real closing brace to show up in the source text. It's supplying its own, on every chunk, so the snapshot you read is always syntactically whole.

Shape-safe is not the same as value-finished

That distinction is the entire point of the example. When the snapshot reads Q sol, it isn't an empty query, and it isn't the final query either. It's a query string that started arriving and hasn't finished, with three more characters still on the wire. A valid snapshot tells you the shape of the object is safe to read right now, that a field exists and won't throw when you access it. It says nothing about whether the value inside that field has stopped changing. Reading jsonSnapshot.q mid-stream will not error, but it also isn't guaranteed to be the value you'll see once the tool call finishes.

What this means for reading fields mid-stream

For anyone handling inputJson events directly, this changes what "safe" means. You don't need to wait for a tool_use_delta done event just to avoid a parse error, since every intermediate snapshot already parses. What you do need to decide is whether your code cares about a field being present versus a field being finished. If you're rendering a live preview of what a tool is about to do, reading early is fine. If you're about to act on a value, like actually running a query, waiting for the value to stop changing still matters, even though the object itself was never in danger of throwing.

Key takeaways

  • A partial JSON snapshot from a streaming tool call in the Anthropic TypeScript SDK is a valid JS object on every chunk, not just at the end.
  • The parser tracks every open object and array on a stack and closes each one with a zero-value default the instant a chunk ends.
  • A four-chunk streaming example of the query "solar" produces four different snapshots, each one syntactically complete.
  • "Shape-safe" means a field is safe to read without throwing; it does not mean the value inside it has finished changing.
  • You can read fields from jsonSnapshot mid-stream without waiting for the done event, as long as you know the value may still grow.

Try it yourself

If you're streaming a tool call with the Anthropic TypeScript SDK and handling inputJson events, take a value you're reading mid-stream and check whether your code assumes it's finished just because it parsed. Humanitarians AI's Claude Basics playlist covers this kind of SDK mechanic in short, focused videos for developers building on Claude.

Chapters

  1. 0:00This half-finished string must be broken, right?
  2. 0:12The natural guess: it behaves the same way
  3. 0:27The anchor: four chunks of one query
  4. 0:43Why: the stack seals itself shut
  5. 0:59The anchor returns: shape safe, value still growing
  6. 1:16Carry-out
  7. 1:24Your turn
  8. 1:46Outro
Full transcript(auto-generated, with timestamps)

This half-finished string must be broken, right?

[0:00]Someone assumes a half-finished JSON string must be broken until the brace arrives. It isn't the SDK hands back a usable object after every chunk. So, how does a partial string already parse as one?

The natural guess: it behaves the same way

[0:12]When Claude streams a tool called JSON, parse demands a complete document. Feed it a half-finished string and it throws. So, the natural guess is that a streaming snapshot behaves the same way, broken or empty until the brace lands. Read it early and you'd expect an error, not an object. Here's the concrete case.

The anchor: four chunks of one query

[0:28]A search tool streams the argument Q solar across four chunks. On input JSON, fires with JSON snapshot equal to then Q, then Q sol, then Q solar. Four snapshots and every single one already a complete parsable object. Here's why the

Why: the stack seals itself shut

[0:43]Parser keeps a stack of every object and array it has opened. The instant a chunk ends, it closes each open structure with a zero value default, an empty string, an empty object, and hands back whatever that produces. Nothing waits for the real closing brace. The parser supplies its own. So, back to the search call

The anchor returns: shape safe, value still growing

[1:00]Isn't an empty query. It's a query string that hasn't started arriving yet. And Q sol isn't the final query either. Three more characters are still on the wire. A valid snapshot tells you the shape is safe to read. It doesn't tell you the value inside has stopped changing. The parser closes every open

Carry-out

[1:16]Structure for you. So, a valid snapshot tells you the shape is safe to read, not that the values inside it are finished. Your turn. Here's the prompt. Read it

Your turn

[1:25]With me. I'm streaming a tool call with the Anthropic TypeScript SDK and I see partial JSON arriving via the input JSON event. Walk me through why each chunk's JSON snapshot is already a valid JS object before the closing brace arrives, and show me how to read a field from it safely midstream without waiting for the tool use delta done event. Liam Infobear. Why partial JSON can be a

Outro

[1:46]Valid object before the closing brace arrives. Liam Infobear.

More from Claude

Humanitarians AI Lyrical Literacy Project