cube-js/cube · error
No pre-aggregation partitions were built yet for the pre-agg
Error message
No pre-aggregation partitions were built yet for the pre-aggregation serving this query and this API instance wasn't set up to build pre-aggregations. Please make sure your refresh worker is configured correctly, running, pre-aggregation tables are built and all pre-aggregation refresh settings like timezone match. Expected table name patterns: ${expectedTableNames.join(', ')} What it means
In PreAggregationPartitionRangeLoader.loadPreAggregations, when externalRefresh is true the instance only serves partitions built by the refresh worker. If the loaded results list is empty (no partitions found for any partition loader), it throws the same 'no partitions built yet' guidance message, listing the expected table name patterns so the user can compare against what was actually built.
Source
Thrown at packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationPartitionRangeLoader.ts:255
...result,
partitionRange: partitionRanges[i]
};
}));
return { loadResults: resolveResults.filter(res => res !== null), partitionLoaders };
};
// eslint-disable-next-line prefer-const
let loadResultAndLoaders = await loadPreAggregationsByPartitionRanges(await this.partitionRanges());
if (this.options.externalRefresh && loadResultAndLoaders.loadResults.length === 0) {
loadResultAndLoaders = await loadPreAggregationsByPartitionRanges(await this.partitionRanges(true));
// In case there are no partitions ready at matched time dimension intersection then no data can be retrieved.
// We need to provide any table so query can just execute successfully.
if (loadResultAndLoaders.loadResults.length > 0) {
loadResultAndLoaders.loadResults = [loadResultAndLoaders.loadResults[loadResultAndLoaders.loadResults.length - 1]];
}
}
if (this.options.externalRefresh && loadResultAndLoaders.loadResults.length === 0) {
throw new Error(
// eslint-disable-next-line no-use-before-define
PreAggregations.noPreAggregationPartitionsBuiltMessage(loadResultAndLoaders.partitionLoaders.map(p => p.preAggregation))
);
}
let { loadResults } = loadResultAndLoaders;
let lambdaTable: InlineTable;
let emptyResult = false;
if (this.preAggregation.rollupLambdaId) {
if (this.lambdaQuery && loadResults.length > 0) {
const { buildRangeEnd, targetTableName } = loadResults[loadResults.length - 1];
const lambdaTypes = await this.loadCache.getTableColumnTypes(this.preAggregation, targetTableName);
lambdaTable = await this.downloadLambdaTable(buildRangeEnd, lambdaTypes);
}
const rollupLambdaResults = this.preAggregationsTablesToTempTables.filter(tempTableResult => tempTableResult[1].rollupLambdaId === this.preAggregation.rollupLambdaId);
const filteredResults = loadResults.filter(View on GitHub (pinned to 7d981676b3)
Solutions
- Verify the refresh worker is configured and running, and that it built partitions covering the queried range.
- Compare the expected table name patterns in the error with actual tables in the store; rebuild if definitions changed.
- Ensure timezone and dateRangeAlign/granularity settings match between the refresh worker and queries.
- Expand the query's date range to intersect built partitions, or configure the worker to build through now.
- Set externalRefresh=false on this instance if it should build pre-aggregations on demand instead.
Example fix
// before
checkAuthLock: query with externalRefresh and no worker
// after
// schedule refresh in cube.js server
app.listen(...); // plus
preAggregationsSchema: [{ ... scheduledRefresh: true }] and running refresh worker Defensive patterns
Strategy: try-catch
Validate before calling
const tables = await externalDriver.tables();
const expected = expectedTableNames();
if (externalRefresh && !expected.some(p => tables.some(t => t.startsWith(p)))) {
throw new Error('Refresh worker has not built partitions for this query range');
} Try / catch
try {
return await partitionRangeLoader.loadPreAggregations();
} catch (e) {
if (String(e.message).includes('No pre-aggregation partitions were built yet')) {
// ensure refresh worker coverage for the query's date range, then retry once
}
throw e;
} Prevention
- Schedule the refresh worker before enabling externalRefresh.
- Ensure partition builds cover the full queried date range (rolling windows).
- Match timezone and granularity across build and query sides.
- Monitor 'expected table name patterns' alerts in logs.
When it happens
Trigger: Querying a partitioned pre-aggregation with externalRefresh=true when the refresh worker hasn't built any matching partitions; all built partitions are outside the query's date range; expected table names differ due to timezone/granularity/definition drift.
Common situations: Refresh worker missing/misconfigured in serverless deployments; query time range extending beyond built partitions (e.g., querying today when worker builds only through yesterday); mismatched timezone settings between build and query; new pre-aggregation added but never built.
Related errors
- No pre-aggregation partitions were built yet for the pre-agg
- Unable to detect column types for pre-aggregation on empty v
- Create table failed: ${e}
- Unsupported table data passed to ${this.constructor}
- Unable to import (as rows) in Cube Store: empty columns. Mos
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/1ec3099abbff2452.
Report an issue: GitHub.