{"record":{"id":"4291013c7ccaf7c4","repo":"cube-js/cube","slug":"unexpected-stream-end-before-row-with-types","errorCode":null,"errorMessage":"Unexpected stream end before row with types","messagePattern":"Unexpected stream end before row with types","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts","lineNumber":419,"sourceCode":"\n      const allRowsIter = (async function* allRowsIter() {\n        for await (const rowsBatch of resultSetStream) {\n          for (const row of rowsBatch) {\n            yield row.json();\n          }\n        }\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) => {","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts#L401-L437","documentation":"The ClickHouse driver uses the JSONCompactEachRowWithNamesAndTypes format, where the response stream must begin with two rows: one containing column names and the next containing column types. This error is thrown when the stream ends before the second (types) row arrives, meaning ClickHouse returned fewer rows than the format guarantees.","triggerScenarios":"Calling downloadQueryResults() which invokes stream(); the allRowsIter yields the first row (names) but next() returns done before a second row — e.g. ClickHouse returns an empty or malformed result body, or the connection is cut off after the first row.","commonSituations":"Network interruptions between driver and ClickHouse; ClickHouse server errors that truncate the response; proxies/load balancers with aggressive timeouts cutting streaming responses; ClickHouse returning a partial body on large result sets; mismatched ClickHouse versions or format support.","solutions":["Check network stability between the driver and ClickHouse (proxies, LB idle/read timeouts) and raise streaming read timeouts","Retry the query; transient truncation is often resolved on retry","Verify the ClickHouse server version supports JSONCompactEachRowWithNamesAndTypes correctly","Capture ClickHouse server logs for the query id at the time of failure to find server-side errors","Upgrade the cubejs-clickhouse-driver package to pick up stream-robustness fixes"],"exampleFix":"// before\ntry {\n  await dataSourceStorage.downloadQueryResults(query, values);\n} catch (e) { /* unhandled: Unexpected stream end before row with types */ }\n// after\ntry {\n  return await driver.downloadQueryResults(query, values);\n} catch (e) {\n  if (String(e.message).includes('Unexpected stream end')) {\n    return driver.downloadQueryResults(query, values); // retry transient truncation\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"try { await driver.downloadQueryResults(q, v); } catch (e) { if (/Unexpected stream end/.test(String(e))) { /* retry */ } else throw e; }","preventionTips":["Ensure stable network to ClickHouse","Raise streaming timeouts"],"tags":["network","streaming","clickhouse","data-truncation"],"backgroundTag":"stream-truncated-early","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}