Skip to content

bug(streaming): SSE /v1/stream emits row DateTime columns zone-less while /v1/query uses RFC3339 Z #372

Description

@EricAndrechek

Area: streaming · query · sdk — bug (timestamp serialization inconsistency) · found via WaveHouse-Stats dogfooding

Expected: a DateTime column serializes identically on every read path — one unambiguous zoned RFC3339 form (…Z) — so a client stitching backfill (/v1/query) + live (/v1/stream) parses both on the same clock, and it matches the SSE frame's own received_timestamp.

Actual: the same event_ts (DateTime64(3,'UTC')) comes back two ways:

  • POST /v1/query → "event_ts":"2026-07-06T14:42:36Z" — RFC3339 Z.
  • GET /v1/stream frame → envelope "received_timestamp":"…Z" (zoned) but the wrapped row column "data":{…,"event_ts":"2026-07-06 14:42:36.000"} — ClickHouse-native (space separator, no zone). Same frame, envelope zoned / row column not.

The stream marshals the row data verbatim (internal/stream/hub.go project() → json.Marshal({… "data": evt.Data})), so a row DateTime keeps its native form, while /v1/query formats through the CH driver to RFC3339. The SDK SSETransport (clients/ts/src/stream/sse.js) passes data through untouched, and JS Date.parse reads a zone-less string as local time.

Impact: any SDK liveQuery consumer (backfill .fetch() + SSE live in one list) lands the two paths on different clocks — in America/New_York a live row's event_ts resolves +4h vs the same instant from /v1/query, sign-flipping by the viewer's UTC offset. Broke both ordering and the "N min ago" label in the Stats live feed (a 2-min-old event rendered "just now"). Every consumer must normalize today. Envelope-keyed logic (e.g. ingest latency off received_timestamp) is unaffected — the bug is row DateTime columns inside data.

Scope: render row DateTime/DateTime64 columns in the SSE data payload with the same formatter /v1/query uses (RFC3339 Z) rather than the driver-default YYYY-MM-DD HH:MM:SS.fff.

Related: #294 (SSE delivery path), #319 (stream-vs-query policy drift — same query/stream-parity theme), WaveHouse-Stats#55 (client-side workaround shipped there)


From WaveHouse-Stats WAVEHOUSE-FEEDBACK.md dogfooding (live curl capture + SDK-path analysis, dev 08c6f19); validated by code-read against ccd7549 (main) on 2026-07-06.

Activity

  1. added
    bugSomething isn't working
    area/apiHTTP handlers, routing, middleware
    area/sdkTypeScript SDK (clients/ts/)
    on Jul 6, 2026
  2. coderabbitai commented on Jul 6, 2026

    @coderabbitai
    🔗 Related PRs

    #124 - chore(api)!: drop hub wildcard fan-out; SSE/WS use ?table= (closes #100) [merged]
    #174 - refactor(table names): handle unsafe table names [closed]
    #177 - feat: caching for local table/scope invalidation [closed]
    #182 - refactor: full api --> ingest --> clickhouse --> dlq refactor [closed]


    🧪 Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  3. self-assigned this
    on Jul 9, 2026
  4. moved this from Backlog to In progress in WaveHouse Task Boardon Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/apiHTTP handlers, routing, middlewarearea/queryStructured query AST, SQL builderarea/sdkTypeScript SDK (clients/ts/)area/streamingSSE / live-query delivery path (/v1/stream)bugSomething isn't working

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions