Skip to content

fix(client): make space after "data:" optional in SSE parser#5306

Open
serhiizghama wants to merge 4 commits into
genkit-ai:mainfrom
serhiizghama:fix/sse-data-prefix-optional-space
Open

fix(client): make space after "data:" optional in SSE parser#5306
serhiizghama wants to merge 4 commits into
genkit-ai:mainfrom
serhiizghama:fix/sse-data-prefix-optional-space

Conversation

@serhiizghama
Copy link
Copy Markdown

Problem

streamFlow (js/genkit/src/client/client.ts) strips a hardcoded "data: " (6 characters) from each SSE event before passing the rest to JSON.parse. Per the SSE spec, the single space after data: is optional — sources are allowed to emit data:foo. When they do (e.g. Spring WebFlux's built-in ServerSentEventHttpMessageWriter), the current parser consumes the first character of the payload and JSON.parse throws:

SyntaxError: Unexpected non-whitespace character after JSON at position 9

Fixes #3728.

Solution

Strip the data: prefix first, then strip at most one optional leading space — matching the SSE spec's "if value starts with a U+0020 SPACE character, remove it from value" rule.

Testing

Added tests/client_test.ts covering both data:{...} (no space) and data: {...} (conventional) event forms. Local run:

$ pnpm test
# tests 127
# pass 127
# fail 0

Per the SSE spec, the single space after "data:" is optional. The
streamFlow parser was hardcoded to strip 6 characters ("data: "),
which corrupted the payload when an upstream emitted spec-compliant
events without the space (e.g. Spring WebFlux's ServerSentEvent writer)
and caused JSON.parse to throw on a truncated string.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the SSE parser in client.ts to correctly handle optional spaces after the data: prefix per the SSE specification and adds corresponding unit tests. A review comment identifies a potential TypeError when calling hasOwnProperty on a null or non-object result from JSON.parse and suggests a guard clause for better robustness.

Comment on lines +151 to 154
const chunk = JSON.parse(payload);
if (chunk.hasOwnProperty('message')) {
sendChunk(chunk.message);
} else if (chunk.hasOwnProperty('result')) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The chunk variable resulting from JSON.parse(payload) could be null or a non-object type (e.g., if the payload is the string "null" or a number). Accessing hasOwnProperty on null will throw a TypeError. Adding a guard clause to ensure chunk is a non-null object improves robustness and prevents potential crashes on unexpected but valid JSON payloads.

      const chunk = JSON.parse(payload);
      if (!chunk || typeof chunk !== 'object') {
        throw new Error('unknown chunk format: ' + JSON.stringify(chunk));
      }
      if (chunk.hasOwnProperty('message')) {
        sendChunk(chunk.message);
      } else if (chunk.hasOwnProperty('result')) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[JS] streamFlow fails to parse events without a space after “data:” (non-compliant with SSE spec)

1 participant