cube-js/cube · error · Error

Dimension-only measure ${measureName} references cubes (${cu

Error message

Dimension-only measure ${measureName} references cubes (${cubeNamesForMeasure}) that lead to row multiplication. Please rewrite it using sub query.

What it means

A 'dimension-only measure' (a measure expression referencing only dimensions) that touches cubes on the multiplied side of a join would double-count rows. Cube throws this Error when more than one cube is involved and at least one of them leads to row multiplication (multiplied join factor).

Source

Thrown at packages/cubejs-schema-compiler/src/adapter/BaseQuery.js:2224

    )(
      memberNamesForMeasure
    );

    let cubeNameToAttach;
    switch (cubeNamesForMeasure.length) {
      case 0:
        // For zero reference measure there's nothing to derive info about measure from
        // So it assume that it's a regular measure, and it will be evaluated on top of join tree
        return [measureName, [{
          multiplied: false,
          measure: m.measure,
        }]];
      case 1:
        [cubeNameToAttach] = cubeNamesForMeasure;
        break;
      default: {
        if (cubeNamesForMeasure.some(cubeName => this.multipliedJoinRowResult(cubeName))) {
          throw new Error(`Dimension-only measure ${measureName} references cubes (${cubeNamesForMeasure}) that lead to row multiplication. Please rewrite it using sub query.`);
        }
        // Dimensions from several cubes, but none of them is on the multiplied
        // side of a join - safe to evaluate the expression on top of join tree
        return [measureName, [{
          multiplied: false,
          measure: m.measure,
        }]];
      }
    }

    const multiplied = this.multipliedJoinRowResult(cubeNameToAttach) || false;

    const attachedMeasure = {
      ...m.measure,
      originalCubeName: m.measure.cubeName,
      cubeName: cubeNameToAttach
    };

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Rewrite the measure as a sub query (subQuery: true with a defined subQuery measure) so aggregation happens before the join.
  2. Restrict the measure's expression to a single cube (attach to one cube) so the multiplied-cube check is bypassed.
  3. Adjust the join so the referenced cube is not on the multiplied side (e.g. use a belongs-to instead of has-many join direction).
  4. Pre-aggregate the dimension expression in the underlying cube's sql or a rollup.

Example fix

// before (dimension-only measure spanning multiplied cubes)
measures: {
  maxEmail: { type: 'max', sql: '${Users.email}' }
}
// after (rewrite as sub query)
measures: {
  maxEmail: {
    type: 'number',
    sql: "SELECT max(email) FROM users WHERE ${filter}",
    subQuery: true
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Prefer subQuery measures when aggregating dimensions from a many-side cube
function dimensionOnlyMeasureIsSafe(measureRefs, multipliedCubes) {
  return !measureRefs.some(c => multipliedCubes.includes(c));
}

Try / catch

try {
  return await cubeApi.load(query);
} catch (e) {
  if (/Dimension-only measure .* row multiplication/.test(e.message)) {
    console.error(`Rewrite ${e.message.match(/Dimension-only measure (\S+)/)?.[1]} as a subQuery measure`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Creating an ad-hoc measure whose expression aggregates only dimensions (e.g. MAX(dim) or a calculated dimension expression) where the referenced cubes include one on the many-side of a join (multipliedJoinRowResult(cubeName) is true) and the measure spans multiple cubes (default case in cubeNameToAttach switch).

Common situations: Schema authors writing calculated measures over dimensions from a joined many-side table; ad-hoc aggregations like SELECT MAX(dim) that cross cubes in fan-out joins.

Related errors


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