Skip to content

SSE text/event-stream serializer drops legitimate falsy data (0/false/'') and id:0 #2026

Description

@kriszyp

Summary

server/serverHelpers/contentTypes.ts's text/event-stream media-type serialize() uses truthiness to decide whether to emit a message's data:/id: lines:

if (message.data) { /* emit data: line */ }
...
if (message.id) { /* emit id: line */ }

Both guards conflate "absent" with "falsy." For data, that silently omits the data: field for legitimate values 0, false, and '' (not just undefined/null). Per the HTML EventSource algorithm, a dispatched message with an empty data buffer is discarded without firing an event — so a client's listener never sees the update at all, with a 200 response and nothing in the logs to flag it.

For id, the same guard drops id: 0, which is a legitimate reconnect cursor — a client resuming from id: 0 re-reads from the start instead of resuming.

Concrete failure scenario

A Resource streams feature-flag state as { event: 'flag', data: false }. The wire frame is event: flag\n\n (no data: line). The browser's EventSource never dispatches the event, so the client silently keeps showing the last truthy value — no error, no log line, 200 status throughout.

Suggested fix

Distinguish absence from falsiness, e.g.:

if (message.data !== undefined && message.data !== null) { /* emit data: line */ }
if (message.id !== undefined && message.id !== null) { /* emit id: line */ }

Provenance

Surfaced by an independent multi-model pre-push review (codex + Grok + Harper-domain lenses) of #1972 (test(server): promote 3 QA server-layer contract anchors). That PR is test-only and deliberately pins the current (buggy) contract as a documented, flagged anchor at integrationTests/server/qa702-sse-event-data.test.ts rather than silently treating it as correct — this issue tracks the actual fix.

🤖 Filed by Claude (dispatch pr-fix agent) while addressing review comments on #1972.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

Priority

P1

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions