{"record":{"id":"e6c502140eff378f","repo":"cube-js/cube","slug":"unexpected-row-and-names-types-length-mismatch-ro","errorCode":null,"errorMessage":"Unexpected row and names/types length mismatch; row ${row.length} vs names ${names.length}","messagePattern":"Unexpected row and names/types length mismatch; row (.+?) vs names (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-clickhouse-driver/src/HydrationStream.ts","lineNumber":38,"sourceCode":"    ) {\n      // convert all numbers into strings\n      return `${value}`;\n    }\n  }\n\n  return value;\n}\n\nexport function transformRow(row: Record<string, unknown>, meta: any) {\n  for (const [fieldName, value] of Object.entries(row)) {\n    const metaForField = meta[fieldName];\n    row[fieldName] = transformValue(metaForField.type, value);\n  }\n}\n\nexport function transformStreamRow(row: Array<unknown>, names: Array<string>, types: Array<string>): Record<string, unknown> {\n  if (row.length !== names.length) {\n    throw new Error(`Unexpected row and names/types length mismatch; row ${row.length} vs names ${names.length}`);\n  }\n\n  return row.reduce<Record<string, unknown>>((rowObj, value, idx) => {\n    const name = names[idx];\n    const type = types[idx];\n    rowObj[name] = transformValue(type, value);\n    return rowObj;\n    // TODO do we actually want Object.create(null) safety? or is it ok to use {}\n  }, Object.create(null));\n}\n","sourceCodeStart":20,"sourceCodeEnd":49,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-clickhouse-driver/src/HydrationStream.ts#L20-L49","documentation":"transformStreamRow() in HydrationStream.ts converts one compact row (array of values) into a keyed object using parallel names and types arrays. This error is thrown when a data row's element count differs from the names array length, i.e. the row cannot be safely mapped to columns.","triggerScenarios":"Inside stream()/downloadQueryResults(), the names/types rows parsed successfully but a subsequent data row has fewer or more elements — only possible with a truncated/corrupt stream body or a non-conforming server response.","commonSituations":"Network truncation mid-body so the last JSON row is cut; a proxy mangling chunks; ClickHouse-compatible servers emitting rows of inconsistent arity; mocked/stubbed responses in tests with wrong row shapes.","solutions":["Re-run the query — a one-off truncated row usually succeeds on retry","Inspect the raw response (curl with FORMAT JSONCompactEachRowWithNamesAndTypes) to find the malformed row","Remove/bypass proxies or middleboxes that alter streaming bodies","Verify server compatibility — use genuine ClickHouse or a version matching the driver's format expectations","Report to the driver maintainers with the query id if a specific query reproducibly produces mismatched rows"],"exampleFix":"// before (mock row with missing column)\n[[1], ['id','name'], ['UInt64','String']] // row has 1 value, names has 2\n// after\n[[1, 'x'], ['id','name'], ['UInt64','String']]","handlingStrategy":"retry","validationCode":"null","typeGuard":"const rowMatchesSchema = (row: unknown[], names: string[]): boolean => row.length === names.length;","tryCatchPattern":"try { return await driver.downloadQueryResults(q, v); }\ncatch (e) {\n  if (String(e.message).includes('row and names/types length mismatch')) return retryWithBackoff(() => driver.downloadQueryResults(q, v));\n  throw e;\n}","preventionTips":["Retry transiently — truncation mid-body is usually intermittent","Bypass or reconfigure proxies that rewrite streaming responses","Use genuine ClickHouse versions matching driver expectations"],"tags":["clickhouse","streaming","malformed-response","hydration"],"backgroundTag":"row-column-count-mismatch","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}