cube-js/cube · error · UserError
Data blending query granularities must match
Error message
Data blending query granularities must match
What it means
For a data blending query (an array of queries blended into one result set), all sub-queries must share exactly one common date granularity (e.g. all 'day' or all 'month'). The gateway extracts the granularities of the normalized queries via getQueryGranularity and throws if more than one distinct granularity is found, because blending rows on differing time buckets is undefined.
Source
Thrown at packages/cubejs-api-gateway/src/gateway.ts:1513
this.log({
type: 'Query Rewrite completed',
queryRewriteId,
normalizedQueries: normalizedQueries.map(q => this.sanitizeQueryForLogging(q)),
duration: Date.now() - startTime,
query
}, context);
normalizedQueries = normalizedQueries.map(q => remapToQueryAdapterFormat(q));
if (normalizedQueries.some((currentQuery) => !currentQuery)) {
throw new Error('queryTransformer returned null query. Please check your queryTransformer implementation');
}
if (queryType === QueryTypeEnum.BLENDING_QUERY) {
const queryGranularity = getQueryGranularity(normalizedQueries);
if (queryGranularity.length > 1) {
throw new UserError('Data blending query granularities must match');
}
if (queryGranularity.length === 0) {
throw new UserError('Data blending query without granularity is not supported');
}
}
return [queryType, normalizedQueries, queryNormalizationResult.map((it) => remapToQueryAdapterFormat(it.normalizedQuery))];
}
protected async sql4sql({
query,
disablePostProcessing,
context,
res,
}: {query: string, disablePostProcessing: boolean} & BaseRequest) {
try {
await this.assertApiScope('sql', context.securityContext);
View on GitHub (pinned to 7d981676b3)
Solutions
- Set the same `granularity` on the timeDimension of every sub-query in the array.
- Derive granularity once from a single UI control and apply it to all blended queries.
- If different granularities are truly needed, issue separate /load requests and blend on the client instead.
Example fix
// before
[{ measures:['a.c'], timeDimensions:[{dimension:'a.date', granularity:'day', dateRange:['2024-01-01','2024-03-01']}] },
{ measures:['b.c'], timeDimensions:[{dimension:'b.date', granularity:'month', dateRange:['2024-01-01','2024-03-01']}] }]
// after
[{ measures:['a.c'], timeDimensions:[{dimension:'a.date', granularity:'month', dateRange:['2024-01-01','2024-03-01']}] },
{ measures:['b.c'], timeDimensions:[{dimension:'b.date', granularity:'month', dateRange:['2024-01-01','2024-03-01']}] }] Defensive patterns
Strategy: validation
Validate before calling
function blendGranularities(queries) {
return [...new Set(queries.flatMap(q => (q.timeDimensions ?? []).map(td => td.granularity).filter(Boolean)))];
}
if (Array.isArray(query) && blendGranularities(query).length > 1) throw new Error('All blended queries must use the same granularity'); Type guard
function hasMatchingGranularity(qs: any[]): boolean {
const gs = new Set(qs.flatMap(q => (q.timeDimensions ?? []).map(td => td.granularity).filter(Boolean)));
return gs.size <= 1;
} Try / catch
try {
return await cubeApi.load(queries);
} catch (e) {
if (String(e?.message).includes('granularities must match')) {
const g = blendGranularities(queries)[0];
return await cubeApi.load(queries.map(q => alignGranularity(q, g)));
}
throw e;
} Prevention
- Drive granularity from a single shared control in the UI, not per-query settings.
- Unit-test blended query builders for granularity consistency.
- Prefer the official client's blending support which normalizes query types.
When it happens
Trigger: POST /cubejs-api/v1/load with an array query (QueryTypeEnum.BLENDING_QUERY) where e.g. query[0].timeDimensions[0].granularity = 'day' and query[1].timeDimensions[0].granularity = 'month', or one uses no granularity while another uses 'week'.
Common situations: Blending two charts with different zoom levels (daily vs monthly); building the query array programmatically and applying granularity only to some sub-queries; UIs that let users pick granularity per metric instead of globally.
Related errors
- Data blending query without granularity is not supported
- Can't find common parent for '${granularityA}' and '${granul
- maskedMembers cannot be provided in the query
- '${queryType}' query type is not supported by the client.Ple
- Unsupported time granularity: ${granularity}
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/b64e341679070245.
Report an issue: GitHub.