{"record":{"id":"44ae109b998b0ad2","repo":"cube-js/cube","slug":"unexpected-x-clickhouse-format-in-response-expect","errorCode":null,"errorMessage":"Unexpected x-clickhouse-format in response: expected ${format}, received ${resultSet.response_headers['x-clickhouse-format']}","messagePattern":"Unexpected x-clickhouse-format in response: expected (.+?), received (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts","lineNumber":294,"sourceCode":"  protected queryResponse(query: string, values: unknown[]): Promise<ResponseJSON<Record<string, unknown>>> {\n    const formattedQuery = sqlstring.format(query, values);\n\n    return this.withCancel(async (connection, queryId, signal) => {\n      try {\n        const format = 'JSON';\n\n        const resultSet = await connection.query({\n          query: formattedQuery,\n          query_id: queryId,\n          format,\n          clickhouse_settings: this.config.clickhouseSettings,\n          abort_signal: signal,\n        });\n\n        // response_headers['x-clickhouse-format'] is optional, but if it exists,\n        // it should match the requested format.\n        if (resultSet.response_headers['x-clickhouse-format'] && resultSet.response_headers['x-clickhouse-format'] !== format) {\n          throw new Error(`Unexpected x-clickhouse-format in response: expected ${format}, received ${resultSet.response_headers['x-clickhouse-format']}`);\n        }\n\n        // We used format JSON, so we expect each row to be Record with column names as keys\n        const results = await resultSet.json<Record<string, unknown>>();\n        return results;\n      } catch (e) {\n        // TODO replace string formatting with proper cause\n        throw new Error(`Query failed: ${e}; query id: ${queryId}`);\n      }\n    });\n  }\n\n  protected normaliseResponse<R = unknown>(res: ResponseJSON<Record<string, unknown>>): Array<R> {\n    if (res.data) {\n      const meta = (res.meta ?? []).reduce<Record<string, { name: string; type: string; }>>(\n        (state, element) => ({ [element.name]: element, ...state }),\n        {}\n      );","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts#L276-L312","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: settings force another format\nquery(`SELECT ...`, { settings: { output_format_json_quote_64bit_integers: 1, ... } })\n// after: keep default JSON format expected by the driver\nquery(`SELECT ...`)","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const rows = await cube.query(query);\n} catch (e) {\n  if (e.message.includes('Unexpected x-clickhouse-format')) {\n    // find proxy/settings rewriting the response format\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["clickhouse","format-mismatch","http"],"backgroundTag":"response-format-mismatch","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}