cube-js/cube · error

Can't refresh pre-aggregation without measures and dimension

Error message

Can't refresh pre-aggregation without measures and dimensions: ${preAggregation.preAggregationName}

What it means

When building the base query used to refresh an originalSql pre-aggregation, RefreshScheduler needs at least one measure or one dimension on the source cube to form a meaningful refresh query. If the cube behind the pre-aggregation defines neither, Cube throws this error because there is nothing to select.

Source

Thrown at packages/cubejs-server-core/src/core/RefreshScheduler.ts:207

      groupedPartitions: partitions.groupedPartitionPreAggregations,
    };
  }

  protected async baseQueryForPreAggregation(
    compilerApi: CompilerApi,
    preAggregation,
    queryingOptions: ScheduledRefreshQueryingOptions
  ) {
    const compilers = await compilerApi.getCompilers();
    const query = await compilerApi.createQueryByDataSource(compilers, queryingOptions);
    if (preAggregation.preAggregation.partitionGranularity || preAggregation.preAggregation.type === 'rollup') {
      return { ...queryingOptions, ...preAggregation.references, preAggregationId: preAggregation.id };
    } else if (preAggregation.preAggregation.type === 'originalSql') {
      const cubeFromPath = query.cubeEvaluator.cubeFromPath(preAggregation.cube);
      const measuresCount = Object.keys(cubeFromPath.measures || {}).length;
      const dimensionsCount = Object.keys(cubeFromPath.dimensions || {}).length;
      if (measuresCount === 0 && dimensionsCount === 0) {
        throw new Error(
          `Can't refresh pre-aggregation without measures and dimensions: ${preAggregation.preAggregationName}`
        );
      }
      return {
        ...queryingOptions,
        ...(
          measuresCount &&
            { measures: [`${preAggregation.cube}.${Object.keys(cubeFromPath.measures)[0]}`] }
        ),
        ...(
          dimensionsCount &&
            { dimensions: [`${preAggregation.cube}.${Object.keys(cubeFromPath.dimensions)[0]}`] }
        )
      };
    } else {
      throw new Error(
        `Scheduled refresh is unsupported for ${preAggregation.preAggregation.type} of ${preAggregation.preAggregationName}`
      );

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Add at least one measure or dimension to the cube referenced by the originalSql pre-aggregation
  2. Remove the originalSql pre-aggregation if the cube intentionally has no measures/dimensions
  3. Change the pre-aggregation type to one with explicit rollup references (rollup with measures/dimensions) that doesn't rely on the cube's own measures/dimensions
  4. Check the referenced cube path (preAggregation.cube) — the counts come from cubeEvaluator.cubeFromPath, so the measures may exist in another cube than you assume

Example fix

// before
cube('Events', {
  sql: 'SELECT * FROM events',
  preAggregations: { main: { type: 'originalSql' } }
});
// after
cube('Events', {
  sql: 'SELECT * FROM events',
  measures: { count: { type: 'count' } },
  preAggregations: { main: { type: 'originalSql' } }
});
Defensive patterns

Strategy: validation

Validate before calling

function validateOriginalSqlPreAgg(cube) {
  const hasMeasures = Object.keys(cube.measures || {}).length > 0;
  const hasDims = Object.keys(cube.dimensions || {}).length > 0;
  if (!hasMeasures && !hasDims) throw new Error(`Cube ${cube.name} needs measures or dimensions for originalSql pre-aggregation`);
}

Type guard

const refreshableOriginalSql = (pa: any): boolean =>
  pa?.preAggregation?.type === 'originalSql' &&
  (Object.keys(pa.cube?.measures ?? {}).length > 0 || Object.keys(pa.cube?.dimensions ?? {}).length > 0);

Try / catch

try {
  await refreshScheduler.refresh(preAggregation);
} catch (e) {
  if (e.message.includes("Can't refresh pre-aggregation without measures and dimensions")) {
    logger.warn(`Skipping ${e.message}`);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Scheduled refresh (or refreshScheduler via baseQuery -> baseQueryForPreAggregation) processes a preAggregation of type 'originalSql' whose cubeFromPath has zero measures AND zero dimensions in its data model.

Common situations: A data model file defines a cube with only pre-aggregations (or only segments/joins) and an originalSql pre-aggregation but no measures/dimensions; typos so measures land outside the cube; auto-generated models stripped of measures.

Related errors


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