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 has

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Ensure the refresh worker is running (scheduledInvoker / dbScheduling or external cron calling the refresh API) and building this pre-aggregation.
  2. Match all refresh settings: timezone, refreshKey, partition granularity and pre-aggregation definition must be identical between refresh worker and API instance.
  3. 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.
  4. Temporarily rebuild the pre-aggregation (buildRollup/pre-aggregations API) to confirm partitions can be produced, then inspect for definition drift.
  5. 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

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


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/3b9b1c173fc805d3. Report an issue: GitHub.