{"record":{"id":"0da880d3293be0cd","repo":"cube-js/cube","slug":"unexpected-stream-end-before-row-with-names","errorCode":null,"errorMessage":"Unexpected stream end before row with names","messagePattern":"Unexpected stream end before row with names","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts","lineNumber":412,"sourceCode":"        throw new Error(`Unexpected x-clickhouse-format in response: expected ${format}, received ${resultSet.response_headers['x-clickhouse-format']}`);\n      }\n\n      // Array<unknown> is okay, because we use fixed JSONCompactEachRowWithNamesAndTypes format\n      // And each row after first two will look like this: [42, \"hello\", [0,1]]\n      // https://clickhouse.com/docs/en/interfaces/formats#jsoncompacteachrowwithnamesandtypes\n      const resultSetStream = resultSet.stream<Array<unknown>>();\n\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);","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts#L394-L430","documentation":"While streaming JSONCompactEachRowWithNamesAndRows data, ClickHouseDriver.stream expects the first row of the stream to be column names and the second to be types. If the async iterator ends before producing the first row (empty body, truncated connection, or error swallowed as empty output), the driver throws 'Unexpected stream end before row with names' because the schema header required to decode subsequent rows is absent.","triggerScenarios":"downloadQueryResults/stream when the ClickHouse response stream closes before emitting any row: empty result body, connection reset mid-response, server error returned as empty stream, or query producing no header row.","commonSituations":"Network interruption between Cube and ClickHouse during large downloads; server crash/timeout during export; proxy buffering timeouts closing idle streams; queries that error after headers were expected but produce empty output.","solutions":["Retry the download — this is often a transient connection drop during streaming","Check ClickHouse server logs around the time of the query for mid-query exceptions","Increase proxy/load-balancer idle timeouts if large exports take long between rows","Reduce result size (partition the export) so the stream completes within network/proxy limits"],"exampleFix":"// before: huge export dropped by proxy idle timeout\nawait downloadQueryResults(query) // 10GB result\n// after: limit rows per export\nawait downloadQueryResults(queryWithTimeWindowAndLimit)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await downloadQueryResults(query);\n} catch (e) {\n  if (e.message === 'Unexpected stream end before row with names') {\n    // transient stream drop: retry with backoff, or chunk the query\n  }\n  throw e;\n}","preventionTips":["Raise proxy/LB idle timeouts for long exports","Chunk large exports by time window to keep streams active","Monitor ClickHouse server logs for mid-query aborts"],"tags":["clickhouse","streaming","connection"],"backgroundTag":"stream-truncated","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}