Area: pipes · api — bug (opaque error / robustness) · found via WaveHouse-Stats dogfooding
Expected: A pipe/query aggregate that yields NaN or ±Inf (e.g. medianIf/avgIf, or a division over an empty in-window set) serializes as null, or returns a clear error naming the offending column.
Actual: POST /v1/pipes/<name> returns 500 {"error":"json: unsupported value: NaN"}. Go's encoding/json can't marshal non-finite floats, so the whole response fails at internal/api/pipes.go:200 (json.Marshal(rows) → err → writeJSONError(500, err.Error())). The message blames "json", not the column/window that produced NaN, and it fails the whole pipe — one empty-window median blanks an entire dashboard card. The same unguarded json.Marshal(rows) path is in internal/api/structured_query.go:208.
Impact: A 7-day range with no matching rows 500'd gh_issue_stats, so every issue tile rendered "NaN". Consumers must defensively guard every aggregate with if(countIf(cond) > 0, agg, NULL) — ClickHouse's nanToNull() does not exist as of CH 26.6, so there's no one-liner shortcut.
Scope: sanitize non-finite floats at the result-marshal boundary (pipes + structured query). Distinct from #271 (that's status-code/retryable classification of CH query errors; this is serialization of a successful result).
Related: #271
From WaveHouse-Stats WAVEHOUSE-FEEDBACK.md dogfooding (WaveHouse-Stats#51, logged 2026-07-02); validated by code-read against 029fe1f on 2026-07-02.
Area: pipes · api — bug (opaque error / robustness) · found via WaveHouse-Stats dogfooding
Expected: A pipe/query aggregate that yields NaN or ±Inf (e.g.
medianIf/avgIf, or a division over an empty in-window set) serializes asnull, or returns a clear error naming the offending column.Actual:
POST /v1/pipes/<name>returns500 {"error":"json: unsupported value: NaN"}. Go'sencoding/jsoncan't marshal non-finite floats, so the whole response fails atinternal/api/pipes.go:200(json.Marshal(rows)→ err →writeJSONError(500, err.Error())). The message blames "json", not the column/window that produced NaN, and it fails the whole pipe — one empty-window median blanks an entire dashboard card. The same unguardedjson.Marshal(rows)path is ininternal/api/structured_query.go:208.Impact: A 7-day range with no matching rows 500'd
gh_issue_stats, so every issue tile rendered "NaN". Consumers must defensively guard every aggregate withif(countIf(cond) > 0, agg, NULL)— ClickHouse'snanToNull()does not exist as of CH 26.6, so there's no one-liner shortcut.Scope: sanitize non-finite floats at the result-marshal boundary (pipes + structured query). Distinct from #271 (that's status-code/retryable classification of CH query errors; this is serialization of a successful result).
Related: #271
From WaveHouse-Stats
WAVEHOUSE-FEEDBACK.mddogfooding (WaveHouse-Stats#51, logged 2026-07-02); validated by code-read against029fe1fon 2026-07-02.