{"record":{"id":"77de74e4c048938c","repo":"cube-js/cube","slug":"preaggregation-cube-preaggregation-preaggreg","errorCode":null,"errorMessage":"'${preAggregation.cube}.${preAggregation.preAggregationName}' referenced by '${cube}.${preAggregationName}' rollupLambda doesn't have partition granularity. Partition granularity is required if multiple rollups are provided.","messagePattern":"'(.+?)\\.(.+?)' referenced by '(.+?)\\.(.+?)' rollupLambda doesn't have partition granularity\\. Partition granularity is required if multiple rollups are provided\\.","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts","lineNumber":1255,"sourceCode":"      });\n      referencedPreAggregations.forEach(preAgg => {\n        references.rollupsReferences.push(preAgg.references);\n      });\n      const lambdaResult = canUsePreAggregation(references);\n      return {\n        ...preAggObj,\n        canUsePreAggregation: lambdaResult.canUse,\n        leafMeasureMatch: lambdaResult.leafMeasureMatch,\n        referencedPreAggregations,\n      };\n    } else {\n      return preAggObj;\n    }\n  }\n\n  public static checkPartitionGranularityDefined(cube: string, preAggregationName: string, preAggregation: PreAggregationForQuery): string {\n    if (!preAggregation.preAggregation.partitionGranularity) {\n      throw new UserError(`'${preAggregation.cube}.${preAggregation.preAggregationName}' referenced by '${cube}.${preAggregationName}' rollupLambda doesn't have partition granularity. Partition granularity is required if multiple rollups are provided.`);\n    }\n    return preAggregation.preAggregation.partitionGranularity;\n  }\n\n  public static memberNameMismatchValidation(preAggA: PreAggregationForQuery, preAggB: PreAggregationForQuery, memberType: 'measures' | 'dimensions' | 'timeDimensions') {\n    const preAggAMemberNames = PreAggregations.memberShortNames(preAggA.references[memberType]);\n    const preAggBMemberNames = PreAggregations.memberShortNames(preAggB.references[memberType]);\n    if (!R.equals(\n      preAggAMemberNames,\n      preAggBMemberNames\n    )) {\n      throw new UserError(`Names for ${memberType} doesn't match between '${preAggA.cube}.${preAggA.preAggregationName}' and '${preAggB.cube}.${preAggB.preAggregationName}': ${JSON.stringify(preAggAMemberNames)} does not equal to ${JSON.stringify(preAggBMemberNames)}`);\n    }\n  }\n\n  private static memberShortNames(memberArray: (string | PreAggregationTimeDimensionReference)[]): string[] {\n    return memberArray.map(member => {\n      if (typeof member !== 'string') {","sourceCodeStart":1237,"sourceCodeEnd":1273,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts#L1237-L1273","documentation":"When a rollupLambda references multiple rollups, every referenced pre-aggregation must define partitionGranularity, since concatenation of partitions requires each source rollup to be partitioned. This static check throws if any referenced pre-aggregation lacks it.","triggerScenarios":"checkPartitionGranularityDefined is called during rollupLambda building with 2+ referenced rollups, and one of them (or one defined via a reference without partitionGranularity) has no partitionGranularity set in its definition.","commonSituations":"Adding a second rollup to an existing lambda while the first/second rollup was never partitioned; pre-aggregations defined before partitionGranularity existed (older schemas); referencing a shared pre-aggregation that other queries use unpartitioned.","solutions":["Add partitionGranularity: 'month' (or day/week/year) to every pre-aggregation referenced by a multi-rollup rollupLambda.","If a rollup should not be partitioned, remove it from the multi-rollup lambda or give it its own lambda.","Audit all rollups listed in rollups arrays for the partitionGranularity key."],"exampleFix":"// before\nordersByMonth: { measures: [CUBE.count], timeDimension: Orders.createdAt, granularity: 'month' }\n// after\nordersByMonth: { measures: [CUBE.count], timeDimension: Orders.createdAt, granularity: 'month', partitionGranularity: 'month' }","handlingStrategy":"validation","validationCode":"// Require partitionGranularity on every rollup referenced by a multi-rollup rollupLambda\nfunction requirePartitionGranularity(def, preAggDefs) {\n  if (def.type === 'rollupLambda' && (def.rollups || []).length > 1) {\n    for (const r of def.rollups) {\n      if (!preAggDefs[r]?.partitionGranularity) throw new Error(`${r} needs partitionGranularity for multi-rollup rollupLambda`);\n    }\n  }\n}","typeGuard":"function isPartitioned(p) { return typeof p?.partitionGranularity === 'string' && p.partitionGranularity.length > 0; }","tryCatchPattern":"try { await cube.query(query); } catch (e) { if (/doesn't have partition granularity/.test(e.message)) { console.error('Add partitionGranularity to the referenced rollup:', e.message); } else throw e; }","preventionTips":["Make partitionGranularity mandatory for any pre-aggregation used in lambdas","Audit legacy pre-aggregations after adding them to a rollups array","Enforce the attribute via a shared pre-aggregation factory function","Test-compile all lambdas in CI"],"tags":["pre-aggregation","rollup-lambda","partition-granularity","missing-attribute"],"backgroundTag":"missing-partition-granularity","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}