Goal
Support ClickHouse 24.8 in a deliberately limited but data-safe mode when JSONStringsEachRowWithProgress / JSONEachRowWithProgress returns row records without a meta record.
The support contract for 24.8 is:
Query execution and faithful Table result display are supported. Features that require ClickHouse result-type metadata are not guaranteed on 24.8.
The primary invariant is: never discard query values because result metadata is unavailable.
Problem
applyStreamLine() currently learns both column names and ClickHouse types only from a {"meta":[...]} line. A row is converted to an array by mapping through result.columns:
if (json.meta) {
result.columns = json.meta.map((m) => ({ name: m.name, type: m.type }));
} else if (json.row) {
result.rows.push(result.columns.map((c) => row[c.name]));
}
On the confirmed 24.8 servers below, no meta line arrives. result.columns therefore remains empty and every successful row becomes [], so the UI silently renders an empty result despite the wire response containing the data.
Confirmed live on pinned images:
24.8.14.39 (OSS)
24.8.14.10547.altinitystable
The exact first ClickHouse 25.x release that emits meta for these formats has not been established. This issue therefore targets the observed protocol behavior rather than guessing a version boundary.
Required behavior
Meta-first streams
Existing behavior must remain unchanged when meta arrives before rows:
- column names come from
meta;
- ClickHouse types come from
meta;
- rows are stored in metadata column order;
- existing typed Table/KPI/chart/log behavior remains unchanged.
Meta-less streams
When a row arrives while result.columns is empty:
- Establish columns from that row's keys, preserving
Object.keys(row) order.
- Represent unavailable ClickHouse types with the existing string field using the explicit sentinel
type: ''.
- Store the row values in that established column order.
- Store all subsequent rows using the same established column order.
- Do not wait or buffer rows in the hope that
meta will arrive later; the reproduced 24.8 stream reaches EOF without metadata.
Conceptually:
if (json.row) {
const row = json.row as Record<string, unknown>;
if (result.columns.length === 0) {
result.columns = Object.keys(row).map((name) => ({ name, type: '' }));
}
// existing row-cap behavior remains in force
result.rows.push(result.columns.map((column) => row[column.name]));
}
The implementation may be structured differently, but the behavior above is required.
Degraded-functionality contract
type: '' means ClickHouse result type is unknown, not String and not an inferred type.
For a meta-less result:
- Table: supported. Column names and raw query values must be displayed faithfully.
- Type display / type-aware cell formatting: may fall back to generic/unknown behavior.
- Automatic chart role/type detection: not part of the 24.8 support guarantee.
- KPI type eligibility / tuple parsing: not part of the 24.8 support guarantee.
- Logs auto-detection: not part of the 24.8 support guarantee.
- Other consumers that require
column.type must fail closed or use their existing unknown-type behavior; they must not throw, silently discard row data, or fabricate a ClickHouse type.
No value-based ClickHouse type inference is required or desired in this issue. In particular, numeric-looking strings, dates, UUIDs, decimals, large integers, enums, etc. must not be assigned synthetic ClickHouse types from their JSON representation.
Non-goals
This issue does not require:
- reconstructing full ClickHouse types from row values;
- an auxiliary metadata query;
- restoring KPI/chart/log feature parity on 24.8;
- identifying the exact first 25.x release containing the upstream metadata change;
- changing
Column.type to optional.
Those can be considered separately if broader old-server support is later required.
Tests
Add regression coverage for the actual failure mode, not only row-before-meta:
- a stream containing one row and EOF with no
meta ever arriving;
- multiple meta-less rows, preserving the first row's column order and every row's values;
- precision-sensitive/string values remain byte-for-byte/value-for-value intact through normalization;
- row-cap behavior still applies on meta-less streams;
- normal
meta -> row behavior remains unchanged;
- representative type-dependent consumers tolerate
type: '' without throwing or inventing typed behavior.
Re-run the existing live compatibility/spike harness against the pinned 24.8 images and verify ordinary Table query results now match expected values.
Documentation / support matrix
Once the regression is verified, document ClickHouse 24.8 as limited support in the support-matrix work (#71), using language equivalent to:
ClickHouse 24.8: Limited support — query execution and Table results are supported. Typed result features such as automatic charts, KPI interpretation, logs detection, and type-aware formatting may be unavailable because these servers do not provide result metadata in the streaming format used by SQL Browser.
Do not describe 24.8 as full-fidelity support.
Acceptance criteria
Background
This was discovered during the #585 / ADR-0005 @clickhouse/client-web validation spike. The current production transport and the official-client candidate reproduced the same incorrect empty-row behavior on 24.8, so this is a production compatibility defect rather than a client-library migration defect.
ClickHouse added metadata to the progress-bearing JSON row formats after the tested 24.8 line. Newer tested servers (26.3 / 26.6) provide metadata and do not require this fallback.
Relates to
Goal
Support ClickHouse 24.8 in a deliberately limited but data-safe mode when
JSONStringsEachRowWithProgress/JSONEachRowWithProgressreturnsrowrecords without ametarecord.The support contract for 24.8 is:
The primary invariant is: never discard query values because result metadata is unavailable.
Problem
applyStreamLine()currently learns both column names and ClickHouse types only from a{"meta":[...]}line. Arowis converted to an array by mapping throughresult.columns:On the confirmed 24.8 servers below, no
metaline arrives.result.columnstherefore remains empty and every successful row becomes[], so the UI silently renders an empty result despite the wire response containing the data.Confirmed live on pinned images:
24.8.14.39(OSS)24.8.14.10547.altinitystableThe exact first ClickHouse 25.x release that emits
metafor these formats has not been established. This issue therefore targets the observed protocol behavior rather than guessing a version boundary.Required behavior
Meta-first streams
Existing behavior must remain unchanged when
metaarrives before rows:meta;meta;Meta-less streams
When a
rowarrives whileresult.columnsis empty:Object.keys(row)order.type: ''.metawill arrive later; the reproduced 24.8 stream reaches EOF without metadata.Conceptually:
The implementation may be structured differently, but the behavior above is required.
Degraded-functionality contract
type: ''means ClickHouse result type is unknown, notStringand not an inferred type.For a meta-less result:
column.typemust fail closed or use their existing unknown-type behavior; they must not throw, silently discard row data, or fabricate a ClickHouse type.No value-based ClickHouse type inference is required or desired in this issue. In particular, numeric-looking strings, dates, UUIDs, decimals, large integers, enums, etc. must not be assigned synthetic ClickHouse types from their JSON representation.
Non-goals
This issue does not require:
Column.typeto optional.Those can be considered separately if broader old-server support is later required.
Tests
Add regression coverage for the actual failure mode, not only
row-before-meta:metaever arriving;meta -> rowbehavior remains unchanged;type: ''without throwing or inventing typed behavior.Re-run the existing live compatibility/spike harness against the pinned 24.8 images and verify ordinary Table query results now match expected values.
Documentation / support matrix
Once the regression is verified, document ClickHouse 24.8 as limited support in the support-matrix work (#71), using language equivalent to:
Do not describe 24.8 as full-fidelity support.
Acceptance criteria
rowrecords populate columns from row keys and preserve all row values.type: ''; no ClickHouse type is inferred from values.metathrough EOF render correctly in Table view.type === ''.24.8.14.39and24.8.14.10547.altinitystablefor ordinary Table queries.@clickhouse/client-webadoption decision.Background
This was discovered during the #585 / ADR-0005
@clickhouse/client-webvalidation spike. The current production transport and the official-client candidate reproduced the same incorrect empty-row behavior on 24.8, so this is a production compatibility defect rather than a client-library migration defect.ClickHouse added metadata to the progress-bearing JSON row formats after the tested 24.8 line. Newer tested servers (26.3 / 26.6) provide metadata and do not require this fallback.
Relates to
docs/ADR-0005-clickhouse-web-client.md— discovery/evidence