cube-js/cube · error

Unable to import (as rows) in Cube Store: empty columns. Mos

Error message

Unable to import (as rows) in Cube Store: empty columns. Most probably, introspection has failed.

What it means

When importing pre-aggregation data as in-memory rows, CubeStoreDriver requires a non-empty columns array to build CREATE TABLE. Empty columns means the introspection step that derives columns from the query result failed or returned nothing.

Source

Thrown at packages/cubejs-cubestore-driver/src/CubeStoreDriver.ts:295

      await this.importStreamingSource(columns, tableData, table, indexes, uniqueKeyColumns, queryTracingObj, externalOptions?.sealAt);
    } else if (tableData.rows) {
      await this.importRows(table, columns, indexes, aggregations, tableData, queryTracingObj);
    } else {
      throw new Error(`Unsupported table data passed to ${this.constructor}`);
    }
  }

  private createIndexString(index: CreateTableIndex) {
    const prefix = {
      regular: '',
      aggregate: 'AGGREGATE '
    }[index.type] || '';
    return `${prefix}INDEX ${index.indexName} (${index.columns.join(',')})`;
  }

  private async importRows(table: string, columns: Column[], indexesSql: any, aggregations: any, tableData: DownloadTableMemoryData, queryTracingObj?: any) {
    if (!columns || columns.length === 0) {
      throw new Error('Unable to import (as rows) in Cube Store: empty columns. Most probably, introspection has failed.');
    }

    await this.createTableWithOptions(table, columns, { indexes: indexesSql, aggregations, buildRangeEnd: queryTracingObj?.buildRangeEnd }, queryTracingObj);
    try {
      const batchSize = 2000; // TODO make dynamic?
      for (let j = 0; j < Math.ceil(tableData.rows.length / batchSize); j++) {
        const currentBatchSize = Math.min(tableData.rows.length - j * batchSize, batchSize);
        const indexArray = Array.from({ length: currentBatchSize }, (v, i) => i);
        const valueParamPlaceholders =
          indexArray.map(i => `(${columns.map((c, paramIndex) => this.param(paramIndex + i * columns.length)).join(', ')})`).join(', ');
        const params = indexArray.map(i => columns
          .map(c => this.toColumnValue(tableData.rows[i + j * batchSize][c.name], c.type)))
          .reduce((a, b) => a.concat(b), []);

        await this.query(
          `INSERT INTO ${table}
        (${columns.map(c => this.quoteIdentifier(c.name)).join(', ')})
        VALUES ${valueParamPlaceholders}`,

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Fix the data model so introspection produces columns (valid measures/dimensions in the rollup).
  2. Check the source driver returns column metadata for the introspection query.
  3. Verify columns array is populated before uploadTable (add an assertion).
  4. Upgrade cubejs packages to aligned versions and retry the pre-aggregation build.

Example fix

// before
await driver.uploadTable('preagg', [], { rows });
// after
if (!columns.length) throw new Error('introspection produced no columns');
await driver.uploadTable('preagg', columns, { rows });
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(columns) || columns.length === 0) {
  throw new Error('Refusing to upload: introspection produced no columns');
}
await driver.uploadTable(table, columns, { rows });

Type guard

function hasColumns(c: unknown): c is Array<{ name: string; type: string }> {
  return Array.isArray(c) && c.length > 0 && c.every(col => typeof (col as any).name === 'string');
}

Try / catch

try {
  await driver.uploadTable(table, columns, { rows });
} catch (e) {
  if (e.message.includes('empty columns')) {
    console.error('Introspection failed: check data model measures/dimensions and source driver metadata');
  }
  throw e;
}

Prevention

When it happens

Trigger: uploadTable called with tableData.rows but columns=[] or null — usually when the schema compiler could not infer columns for the pre-aggregation (e.g. failed introspection query, empty result metadata).

Common situations: Broken schema (measures/dimensions resolving to no columns); DB driver returning empty column metadata; serialization mismatch after upgrading packages.

Related errors


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