{"record":{"id":"6aede1dfd5bbdf9b","repo":"cube-js/cube","slug":"measures-map-m-m-measure-join-refer","errorCode":null,"errorMessage":"'${measures.map(m => m.measure).join(', ')}' reference cubes that lead to row multiplication.","messagePattern":"'(.+?)' reference cubes that lead to row multiplication\\.","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-schema-compiler/src/adapter/BaseQuery.js","lineNumber":2521,"sourceCode":"  aggregateSubQuery(keyCubeName, measures, filters) {\n    filters = filters || this.allFilters;\n    const primaryKeyDimensions = this.primaryKeyNames(keyCubeName).map((k) => this.newDimension(k));\n    const shouldBuildJoinForMeasureSelect = this.checkShouldBuildJoinForMeasureSelect(measures, keyCubeName);\n\n    let keyCubeSql;\n    let keyCubeAlias;\n    let keyCubeInlineLeftJoinConditions;\n    const measureSubQueryDimensions = this.collectFrom(\n      measures,\n      this.collectSubQueryDimensionsFor.bind(this),\n      'collectSubQueryDimensionsFor'\n    );\n\n    if (shouldBuildJoinForMeasureSelect) {\n      const joinHints = this.collectJoinHintsFromMembers(measures);\n      const measuresJoin = this.joinGraph.buildJoin(joinHints);\n      if (measuresJoin.multiplicationFactor[keyCubeName]) {\n        throw new UserError(\n          `'${measures.map(m => m.measure).join(', ')}' reference cubes that lead to row multiplication.`\n        );\n      }\n      keyCubeSql = `(${this.aggregateSubQueryMeasureJoin(keyCubeName, measures, measuresJoin, primaryKeyDimensions, measureSubQueryDimensions)})`;\n      keyCubeAlias = this.cubeAlias(keyCubeName);\n    } else {\n      [keyCubeSql, keyCubeAlias, keyCubeInlineLeftJoinConditions] = this.rewriteInlineCubeSql(keyCubeName);\n    }\n\n    const measureSelectFn = () => measures.map(m => m.selectColumns());\n    const selectedMeasures = shouldBuildJoinForMeasureSelect ? this.evaluateSymbolSqlWithContext(\n      measureSelectFn,\n      {\n        ungroupedAliases: R.fromPairs(measures.map(m => [m.measure, m.aliasName()]))\n      }\n    ) : measureSelectFn();\n    const columnsForSelect = this\n      .dimensionColumns(this.escapeColumnName(QueryAlias.AGG_SUB_QUERY_KEYS))","sourceCodeStart":2503,"sourceCodeEnd":2539,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-schema-compiler/src/adapter/BaseQuery.js#L2503-L2539","documentation":"When Cube builds a join for selected measures in a sub query/aggregation context, it checks whether the join causes row multiplication for the key cube. If measures reference cubes whose join multiplies rows of the key cube, the aggregated result would be wrong, so Cube throws this UserError listing the offending measures.","triggerScenarios":"aggregateSubQueryMeasureJoin path: measures collected for a measure-sub-query span multiple cubes, joinGraph.buildJoin(joinHints) yields measuresJoin.multiplicationFactor[keyCubeName] > 1, i.e. a has-many join path between the key cube and the measures' cubes.","commonSituations":"Sub queries over joined fact tables where measures come from different many-side tables; views mixing measures from fan-out joined cubes; adding a second measure from another fact table to an existing dashboard query.","solutions":["Rewrite one of the measures as a sub query measure so it aggregates independently before joining.","Denormalize the needed value into the key cube (e.g. via a rollup or precomputed column).","Restructure the joins so the measures' cube is on the one-side (belongs-to) relative to the key cube.","Split the query into multiple queries and combine client-side."],"exampleFix":"// before (measure from multiplied joined cube in same query)\nmeasures: { ordersCount: C.count, revenue: Orders.revenue, refunds: Refunds.amount }\n// after (rewrite Refunds.amount as sub query measure)\nmeasures: {\n  ordersCount: Orders.count,\n  revenue: Orders.revenue,\n  refunds: { sql: 'SELECT sum(amount) FROM ${Refunds.sql} WHERE ${Refunds.order_id} = ${Orders.id}', type: 'number', subQuery: true }\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":null,"tryCatchPattern":"try {\n  return await cubeApi.load(query);\n} catch (e) {\n  if (/reference cubes that lead to row multiplication/.test(e.message)) {\n    console.error('Rewrite one of the listed measures as a subQuery measure:', e.message);\n  }\n  throw e;\n}","preventionTips":["Avoid mixing measures from different fact (many-side) tables in one query","Use subQuery measures for independent aggregations","Design joins so shared dimensions sit on the one-side"],"tags":["fanout","join-multiplication","measures"],"backgroundTag":"row-multiplication-fanout","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}