cube-js/cube · error · Error
Unable to detect column types for pre-aggregation on empty v
Error message
Unable to detect column types for pre-aggregation on empty values in readOnly mode.
What it means
detectTypesFromTabular() infers column types from result rows. In readOnly mode there is no other way to detect types, and if the rows array is empty it cannot infer anything, so it throws this explicit error (scanning is bounded by DB_TYPE_DETECTION_MAX_ROWS).
Source
Thrown at packages/cubejs-base-driver/src/type-detection.ts:60
const normalized = v.toString().toLowerCase();
return normalized === 'true' || normalized === 'false';
},
string: (v) => v.length < 256,
text: () => true
};
const MATCHER_TYPES = Object.keys(DbTypeValueMatcher);
// While detecting column types the first row is normally enough, but when it
// holds NULLs we keep scanning further rows until every column has a concrete
// value to infer its type from. This bounds how many rows we inspect in that case.
const DB_TYPE_DETECTION_MAX_ROWS = 100;
export function detectTypesFromTabular(rows: Row[]): TableStructure {
if (rows.length === 0) {
throw new Error(
'Unable to detect column types for pre-aggregation on empty values in readOnly mode.'
);
}
const fields = Object.keys(rows[0]);
// Non-null values sampled per column while scanning rows.
const valuesByField: Record<string, any[]> = {};
for (const field of fields) {
valuesByField[field] = [];
}
const unresolvedFields = new Set(fields);
const rowsToScan = Math.min(rows.length, DB_TYPE_DETECTION_MAX_ROWS);
for (let i = 0; i < rowsToScan; i++) {
const row = rows[i];View on GitHub (pinned to 7d981676b3)
Solutions
- Ensure the source table/partition has data before building the pre-aggregation
- Relax or fix query filters that eliminate all rows
- Provide explicit column types in the schema so runtime type detection is not needed
- If detection is possible, allow the driver to use database metadata (non-readOnly path)
Example fix
// before
const structure = detectTypesFromTabular([]); // throws
// after
if (rows.length === 0) {
structure = columns.map(c => ({ name: c.name, type: 'text' })); // explicit defaults
} else {
structure = detectTypesFromTabular(rows);
} Defensive patterns
Strategy: validation
Validate before calling
if (rows.length === 0) {
throw new Error('Source query returned no rows; supply explicit column types or fix filters before building the pre-agg');
}
const structure = detectTypesFromTabular(rows); Type guard
function hasRows(rows: Row[]): rows is [Row, ...Row[]] {
return rows.length > 0;
} Try / catch
try {
structure = detectTypesFromTabular(rows);
} catch (e) {
if (/Unable to detect column types/.test(e.message)) {
structure = explicitSchemaTypes();
} else throw e;
} Prevention
- Define explicit column types in the data model to avoid runtime detection
- Guard against empty tables/partitions before pre-agg builds
- Check filters for over-restriction that removes all rows
- Seed or validate data presence in CI before build jobs
When it happens
Trigger: Calling types()/detectTypesFromTabular() with an empty rows array — e.g. a pre-aggregation query over an empty table or a filter matching no rows.
Common situations: Pre-aggregation build against an empty source table, an overly restrictive filter eliminating all rows, or a partition with no data.
Related errors
- Create table failed: ${e}
- Unsupported table data passed to ${this.constructor}
- Unable to import (as rows) in Cube Store: empty columns. Mos
- Unsupported export bucket type: ${this.config.bucketType}
- MySQL can not work with table names longer than 64 symbols.
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/0c2bf514852e68f7.
Report an issue: GitHub.