I was building a streaming chat interface against MonkeyCode's free model access and its free server option, and the first few test runs went so smoothly that I stopped thinking about the transport layer entirely. The server sent back clean SSE events, each one a complete JSON object carrying a token of text, and my parser happily decoded them one by one. Then I asked for a longer response, and the terminal lit up with json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) on the second event.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The full response, captured to a file, was valid JSON. The model had not failed. My parser had failed because it assumed something the SSE protocol never guarantees: that each event contains a complete, self-contained JSON document.

What the Stream Actually Looked Like

Server-Sent Events is a simple framing protocol. Each event is a set of key: value lines terminated by a blank line, and the data: field carries the payload. When a model streams tokens, the server does not promise to flush one complete JSON object per event. It flushes whatever bytes are ready, which means a single logical object can be split across several events, or several objects can be packed into one event.