cube-js/cube · error
Unexpected x-clickhouse-format in response: expected ${forma
Error message
Unexpected x-clickhouse-format in response: expected ${format}, received ${resultSet.response_headers['x-clickhouse-format']} What it means
In ClickHouseDriver.queryResponse, after executing a query the driver checks the optional `x-clickhouse-format` response header. The comment states it's optional, but if present it must match the requested format (usually JSON). A mismatch means ClickHouse (or an intermediary) returned data in a different format than the client will try to parse, so the driver throws to prevent corrupt result parsing.
Source
Thrown at packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts:294
protected queryResponse(query: string, values: unknown[]): Promise<ResponseJSON<Record<string, unknown>>> {
const formattedQuery = sqlstring.format(query, values);
return this.withCancel(async (connection, queryId, signal) => {
try {
const format = 'JSON';
const resultSet = await connection.query({
query: formattedQuery,
query_id: queryId,
format,
clickhouse_settings: this.config.clickhouseSettings,
abort_signal: signal,
});
// response_headers['x-clickhouse-format'] is optional, but if it exists,
// it should match the requested format.
if (resultSet.response_headers['x-clickhouse-format'] && resultSet.response_headers['x-clickhouse-format'] !== format) {
throw new Error(`Unexpected x-clickhouse-format in response: expected ${format}, received ${resultSet.response_headers['x-clickhouse-format']}`);
}
// We used format JSON, so we expect each row to be Record with column names as keys
const results = await resultSet.json<Record<string, unknown>>();
return results;
} catch (e) {
// TODO replace string formatting with proper cause
throw new Error(`Query failed: ${e}; query id: ${queryId}`);
}
});
}
protected normaliseResponse<R = unknown>(res: ResponseJSON<Record<string, unknown>>): Array<R> {
if (res.data) {
const meta = (res.meta ?? []).reduce<Record<string, { name: string; type: string; }>>(
(state, element) => ({ [element.name]: element, ...state }),
{}
);View on GitHub (pinned to 7d981676b3)
Solutions
- Compare expected vs received format in the message and find what rewrote the response (proxy, settings, custom query)
- Remove/fix clickhouse_settings that override the output format (e.g. output_format_* settings)
- Check any intermediary (ChProxy, ingress) that rewrites ClickHouse responses or their headers
- Upgrade @clickhouse/client and driver to aligned versions if a server/client format negotiation changed
Example fix
// before: settings force another format
query(`SELECT ...`, { settings: { output_format_json_quote_64bit_integers: 1, ... } })
// after: keep default JSON format expected by the driver
query(`SELECT ...`) Defensive patterns
Strategy: validation
Try / catch
try {
const rows = await cube.query(query);
} catch (e) {
if (e.message.includes('Unexpected x-clickhouse-format')) {
// find proxy/settings rewriting the response format
}
throw e;
} Prevention
- Don't set clickhouse_settings that alter output format
- Avoid proxies that rewrite ClickHouse response bodies/headers
- Keep @clickhouse/client and ClickHouse server versions compatible
When it happens
Trigger: A query sent via query() whose response carries an x-clickhouse-format header differing from the requested `format` — e.g. a proxy/gateway rewriting the format, ClickHouse returning an error body with a different format header, or custom clickhouse_settings forcing another output format.
Common situations: ClickHouse behind an API gateway/ChProxy altering response headers; server-side FORMAT clause injected via settings; version mismatches where the client expects JSON but the server emits JSONCompact; error responses that still include a format header.
Related errors
- Query param is required
- HTTP error! status: ${response.status}
- unexpected response ${response.statusText}
- Connection check failed: ${errorMessage}
- Query failed: ${e}; query id: ${queryId}
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/44ae109b998b0ad2.
Report an issue: GitHub.