{"record":{"id":"356c66b04bb17b4a","repo":"cube-js/cube","slug":"unexpected-names-and-types-length-mismatch-names","errorCode":null,"errorMessage":"Unexpected names and types length mismatch; names ${names.length} vs types ${types.length}","messagePattern":"Unexpected names and types length mismatch; names (.+?) vs types (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts","lineNumber":425,"sourceCode":"        }\n      }());\n\n      const first = await allRowsIter.next();\n      if (first.done) {\n        throw new Error('Unexpected stream end before row with names');\n      }\n      // JSONCompactEachRowWithNamesAndTypes: expect first row to be column names as string\n      const names = first.value as Array<string>;\n\n      const second = await allRowsIter.next();\n      if (second.done) {\n        throw new Error('Unexpected stream end before row with types');\n      }\n      // JSONCompactEachRowWithNamesAndTypes: expect first row to be column names as string\n      const types = second.value as Array<string>;\n\n      if (names.length !== types.length) {\n        throw new Error(`Unexpected names and types length mismatch; names ${names.length} vs types ${types.length}`);\n      }\n\n      const dataRowsIter = (async function* () {\n        for await (const row of allRowsIter) {\n          yield transformStreamRow(row, names, types);\n        }\n      }());\n      const rowStream = Readable.from(dataRowsIter);\n\n      return {\n        rowStream,\n        types: names.map((name, idx) => {\n          const type = types[idx];\n          return {\n            name,\n            type: this.toGenericType(type),\n          };\n        }),","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts#L407-L443","documentation":"In the JSONCompactEachRowWithNamesAndTypes response, the first row must be column names and the second row column types, and both must have the same number of elements. This error is thrown when the names row and types row lengths diverge, indicating a malformed or unexpected response from ClickHouse.","triggerScenarios":"Calling downloadQueryResults()/stream(); after reading the names row, the types row (second.value) has a different element count than names.length — only possible with a corrupted, non-standard, or intercepted response body.","commonSituations":"A proxy or middlebox rewriting/chunking the response incorrectly; a custom ClickHouse-compatible server that emits rows with inconsistent arity; manually mocked or stubbed ClickHouse responses in tests; format handling bugs after driver/server version changes.","solutions":["Query ClickHouse directly with FORMAT JSONCompactEachRowWithNamesAndTypes to inspect the raw response for inconsistent row lengths","Remove or reconfigure proxies/middlewares that could alter the streamed body","Verify the endpoint is a genuine ClickHouse server (not an incompatible shim) and versions match driver expectations","Upgrade the cubejs-clickhouse-driver package; if it persists, report with the query id"],"exampleFix":"// before (mock in tests returning inconsistent rows)\n['id', 'name'] // names row\n['UInt64']     // types row — wrong arity, triggers error\n// after\n['id', 'name']\n['UInt64', 'String']","handlingStrategy":"validation","validationCode":"// Sanity-check the server responds correctly to the format\nconst res = await fetch(`${clickhouseUrl}/?query=${encodeURIComponent('SELECT 1 FORMAT JSONCompactEachRowWithNamesAndTypes')}`);\nconst rows = await res.json();\nif (!Array.isArray(rows) || rows.length < 2 || rows[0].length !== rows[1].length) throw new Error('Incompatible ClickHouse format response');","typeGuard":"const isWellFormedNamesTypes = (r: unknown): r is [string[], string[]] =>\n  Array.isArray(r) && r.length >= 2 && Array.isArray(r[0]) && Array.isArray(r[1]) && r[0].length === r[1].length;","tryCatchPattern":"try { return await driver.downloadQueryResults(q, v); }\ncatch (e) {\n  if (String(e.message).includes('names and types length mismatch')) throw new Error('ClickHouse returned malformed response; check server/proxy', { cause: e });\n  throw e;\n}","preventionTips":["Test against the real ClickHouse server, not hand-rolled mocks","Avoid middleboxes that rewrite streaming bodies","Pin supported ClickHouse versions"],"tags":["clickhouse","streaming","malformed-response","protocol"],"backgroundTag":"malformed-query-response","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}