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
When externalRefresh is enabled, this API instance only reads pre-aggregation partitions built by a refresh worker; it never builds them itself. loadPreAggregation throws this when no version entry matching the pre-aggregation's structure version exists (i.e., no partitions built yet) and throwOnMissingPartition is set, telling the user their refresh worker setup isn't producing the expected tables.
Source
Thrown at packages/cubejs-query-orchestrator/src/orchestrator/PreAggregationLoader.ts:171
? this.preAggregationQueryKey(refreshKeyValues)
: undefined,
};
} else {
// Serve whatever version already exists rather than making this request wait for a build
const structureVersion = getStructureVersion(this.preAggregation);
const getVersionsStarted = new Date();
const { byStructure } = await this.loadCache.getVersionEntries(this.preAggregation);
this.logger('Load PreAggregations Tables', {
preAggregation: this.preAggregation,
requestId: this.requestId,
duration: (new Date().getTime() - getVersionsStarted.getTime())
});
const versionEntryByStructureVersion = byStructure[`${this.preAggregation.tableName}_${structureVersion}`];
if (this.externalRefresh) {
if (!versionEntryByStructureVersion && throwOnMissingPartition) {
// eslint-disable-next-line no-use-before-define
throw new Error(PreAggregations.noPreAggregationPartitionsBuiltMessage([this.preAggregation]));
}
if (!versionEntryByStructureVersion) {
return null;
} else {
// the rollups are being maintained independently of this instance of cube.js
// immediately return the latest rollup data that instance already has
return {
targetTableName: this.targetTableName(versionEntryByStructureVersion),
refreshKeyValues: [],
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
buildRangeEnd: versionEntryByStructureVersion.build_range_end,
};
}
}
if (versionEntryByStructureVersion) {
// this triggers an asynchronous/background load of the pre-aggregation but immediately
// returns the latest data it already hasView on GitHub (pinned to 7d981676b3)
Solutions
- Ensure the refresh worker is running (scheduledInvoker / dbScheduling or external cron calling the refresh API) and building this pre-aggregation.
- Match all refresh settings: timezone, refreshKey, partition granularity and pre-aggregation definition must be identical between refresh worker and API instance.
- Check the store: built partition tables should exist in the shared external store; list tables and compare against the expected table name patterns in the message.
- Temporarily rebuild the pre-aggregation (buildRollup/pre-aggregations API) to confirm partitions can be produced, then inspect for definition drift.
- Disable throwOnMissingPartition or externalRefresh only if you intend this instance to build pre-aggregations itself.
Example fix
// before (querying before any build)
cubejsServer.event('rollupOnly')
// after: run a refresh worker that builds first
scheduledRefreshContexts / refreshWorker: { enabled: true } // then query Defensive patterns
Strategy: try-catch
Validate before calling
// before querying, confirm partitions exist in the external store
const tables = await externalDriver.tables();
const hasPartition = tables.some(t => t.startsWith(expectedTablePrefix));
if (externalRefresh && !hasPartition) throw new Error('No partitions built yet: run refresh worker first'); Try / catch
try {
return await preAggregations.loadPreAggregation({...});
} catch (e) {
if (String(e.message).includes('No pre-aggregation partitions were built yet')) {
// trigger refresh worker / inform user to configure refresh
throw new Error('Configure and run your refresh worker, then retry the query.');
}
throw e;
} Prevention
- Always run a refresh worker when externalRefresh=true.
- Keep timezone, refreshKey and rollup definitions identical between worker and API.
- Alert when built table names stop matching expected patterns.
- Rebuild pre-aggregations after changing rollup definitions.
When it happens
Trigger: Query executed against an API instance with externalRefresh=true before any refresh worker has built the pre-aggregation; structureVersion mismatch (pre-aggregation definition/timezone changed after partitions were built); refresh worker not running or building into a different store.
Common situations: Deploying the API with externalRefresh enabled but forgetting to schedule the refresh worker; refresh settings (timezone, refreshKey, date range) differing from the query's; rollup definition changed so built partitions no longer match the expected structure version; pre-aggregation tables exist under different names than the expected patterns.
Related errors
- No pre-aggregation partitions were built yet for the pre-agg
- Pre-aggregation '${this.preAggregation.tableName}' requested
- Unable to detect column types for pre-aggregation on empty v
- Create table failed: ${e}
- Unsupported table data passed to ${this.constructor}
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/3b9b1c173fc805d3.
Report an issue: GitHub.