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

  1. Re-run the query — a one-off truncated row usually succeeds on retry
  2. Inspect the raw response (curl with FORMAT JSONCompactEachRowWithNamesAndTypes) to find the malformed row
  3. Remove/bypass proxies or middleboxes that alter streaming bodies
  4. Verify server compatibility — use genuine ClickHouse or a version matching the driver's format expectations
  5. 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

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


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/e6c502140eff378f. Report an issue: GitHub.