cube-js/cube · error · PostgresError
${this.constructor} driver supports only rows upload
Error message
${this.constructor} driver supports only rows upload What it means
PostgresDriver.uploadTableWithIndexes only supports uploading data held in memory as rows. If the DownloadTableMemoryData passed in has no 'rows' array (e.g. it only holds a CSV file reference or other lazy form), the driver throws because it cannot stream non-row data into PostgreSQL.
Source
Thrown at packages/cubejs-postgres-driver/src/PostgresDriver.ts:489
return this.tableColumnTypesWithPrecision(table);
}
protected override toGenericType(columnType: string, precision?: number | null, scale?: number | null): GenericDataBaseType {
return PostgresToGenericType[columnType.toLowerCase()] || super.toGenericType(columnType, precision, scale);
}
public readOnly() {
return !!this.config.readOnly;
}
public async uploadTableWithIndexes(
table: string,
columns: TableStructure,
tableData: DownloadTableMemoryData,
indexesSql: IndexesSQL
) {
if (!tableData.rows) {
throw new PostgresError(`${this.constructor} driver supports only rows upload`);
}
await this.createTable(table, columns);
try {
await this.query(
`INSERT INTO ${table}
(${columns.map(c => this.quoteIdentifier(c.name)).join(', ')})
SELECT * FROM UNNEST (${columns.map((c, columnIndex) => `${this.param(columnIndex)}::${this.fromGenericType(c.type)}[]`).join(', ')})`,
columns.map(c => tableData.rows.map(r => r[c.name]))
);
for (let i = 0; i < indexesSql.length; i++) {
const [query, p] = indexesSql[i].sql;
await this.query(query, p);
}
} catch (e) {
await this.dropTable(table);View on GitHub (pinned to 7d981676b3)
Solutions
- Ensure the data source populates tableData.rows before calling uploadTableWithIndexes
- Use a download/driver pipeline that produces in-memory rows (e.g. DownloadTableMemoryData with rows loaded)
- If using unload/CSV flows, use a driver path that supports them instead of the rows-only Postgres upload
Example fix
// before
await driver.uploadTableWithIndexes(table, columns, { files: csvFiles }, indexes);
// after
const tableData = await sourceDriver.downloadTable(table); // materializes rows
await driver.uploadTableWithIndexes(table, columns, tableData, indexes); Defensive patterns
Strategy: validation
Validate before calling
function assertRowsUpload(tableData) {
if (!tableData || !Array.isArray(tableData.rows)) {
throw new Error('uploadTableWithIndexes requires DownloadTableMemoryData with rows');
}
}
assertRowsUpload(tableData); Type guard
const hasRows = (td) => typeof td === 'object' && td !== null && Array.isArray(td.rows) && td.rows.length >= 0;
Try / catch
try {
await driver.uploadTableWithIndexes(table, columns, tableData, indexes);
} catch (e) {
if (String(e.message).includes('supports only rows upload')) {
tableData = await sourceDriver.downloadTable(table); // materialize rows
await driver.uploadTableWithIndexes(table, columns, tableData, indexes);
} else throw e;
} Prevention
- Ensure the download step materializes rows before uploading to Postgres
- Don't pass CSV-file-based DownloadTableMemoryData to the Postgres driver
- Test pre-aggregation upload flows end-to-end after changing source drivers
When it happens
Trigger: Calling uploadTableWithIndexes (directly or via the pre-aggregation upload pipeline) with tableData whose rows property is undefined/null — e.g. data downloaded in a non-row format or an incompatible driver produced the DownloadTableMemoryData.
Common situations: Custom or misconfigured download drivers returning data without materialized rows; rolling up pre-aggregations across drivers where the source driver's unload output is passed to the Postgres driver; older code paths that populate DownloadTableMemoryData differently.
Related errors
- No job description provided
- Invalid Job query format: ${error.message || error.toString(
- A user's selector doesn't match any of the pre-aggregations
- The '${query.action}' action type doesn't supported.
- Cannot parse selector date range ${selector.dateRange}
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/0ea29a13bd11e693.
Report an issue: GitHub.