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
- Fix the data model so introspection produces columns (valid measures/dimensions in the rollup).
- Check the source driver returns column metadata for the introspection query.
- Verify columns array is populated before uploadTable (add an assertion).
- 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
- Verify pre-aggregation definitions compile and reference existing measures/dimensions.
- Test introspection against the source DB in dev before production builds.
- Assert columns non-empty at the boundary before uploadTable.
- Keep cubejs-schema-compiler and drivers up to date.
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
- Unsupported table data passed to ${this.constructor}
- Unable to import (as csv) in Cube Store: empty columns. Most
- Unable to import (as stream) in Cube Store: empty columns. M
- Unable to detect column types for pre-aggregation on empty v
- Create table failed: ${e}
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/e1c5dd63a31549f2.
Report an issue: GitHub.