cube-js/cube · error
Unexpected row and names/types length mismatch; row ${row.le
Error message
Unexpected row and names/types length mismatch; row ${row.length} vs names ${names.length} What it means
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.
Source
Thrown at packages/cubejs-clickhouse-driver/src/HydrationStream.ts:38
) {
// convert all numbers into strings
return `${value}`;
}
}
return value;
}
export function transformRow(row: Record<string, unknown>, meta: any) {
for (const [fieldName, value] of Object.entries(row)) {
const metaForField = meta[fieldName];
row[fieldName] = transformValue(metaForField.type, value);
}
}
export function transformStreamRow(row: Array<unknown>, names: Array<string>, types: Array<string>): Record<string, unknown> {
if (row.length !== names.length) {
throw new Error(`Unexpected row and names/types length mismatch; row ${row.length} vs names ${names.length}`);
}
return row.reduce<Record<string, unknown>>((rowObj, value, idx) => {
const name = names[idx];
const type = types[idx];
rowObj[name] = transformValue(type, value);
return rowObj;
// TODO do we actually want Object.create(null) safety? or is it ok to use {}
}, Object.create(null));
}
View on GitHub (pinned to 7d981676b3)
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
Example fix
// before (mock row with missing column) [[1], ['id','name'], ['UInt64','String']] // row has 1 value, names has 2 // after [[1, 'x'], ['id','name'], ['UInt64','String']]
Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
const rowMatchesSchema = (row: unknown[], names: string[]): boolean => row.length === names.length;
Try / catch
try { return await driver.downloadQueryResults(q, v); }
catch (e) {
if (String(e.message).includes('row and names/types length mismatch')) return retryWithBackoff(() => driver.downloadQueryResults(q, v));
throw e;
} Prevention
- Retry transiently — truncation mid-body is usually intermittent
- Bypass or reconfigure proxies that rewrite streaming responses
- Use genuine ClickHouse versions matching driver expectations
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unexpected names and types length mismatch; names ${names.le
- Unexpected stream end before row with names
- Unexpected stream end before row with types
- Stream query failed: ${e}; query id: ${queryId}
- options.stream must be a function
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/e6c502140eff378f.
Report an issue: GitHub.