cube-js/cube · error · Error
Can't find common parent for '${granularityA}' and '${granul
Error message
Can't find common parent for '${granularityA}' and '${granularityB}' What it means
Thrown by the granularity-hierarchy helper that computes the common parent granularity of two granularities. It walks both granularity hierarchies to the deepest shared index; if there is no shared prefix (lastIndex <= 0 and hierarchies differ), no common parent exists and it throws.
Source
Thrown at packages/cubejs-schema-compiler/src/adapter/BaseQuery.js:1973
return granularityB;
}
if (!granularityB) {
return granularityA;
}
if (granularityA === granularityB) {
return granularityA;
}
const aHierarchy = R.reverse(this.granularityParentHierarchy(granularityA));
const bHierarchy = R.reverse(this.granularityParentHierarchy(granularityB));
let lastIndex = Math.max(
aHierarchy.findIndex((g, i) => g !== bHierarchy[i]),
bHierarchy.findIndex((g, i) => g !== aHierarchy[i])
);
if (lastIndex === -1 && aHierarchy.length === bHierarchy.length) {
lastIndex = aHierarchy.length - 1;
}
if (lastIndex <= 0) {
throw new Error(`Can't find common parent for '${granularityA}' and '${granularityB}'`);
}
return aHierarchy[lastIndex - 1];
}
overTimeSeriesQuery(baseQueryFn, cumulativeMeasure, fromRollup) {
const dateJoinCondition = cumulativeMeasure.dateJoinCondition();
const uniqDateJoinCondition = R.uniqBy(djc => djc[0].dimension, dateJoinCondition);
const cumulativeMeasures = [cumulativeMeasure];
if (!this.timeDimensions.find(d => d.granularity)) {
const filters = this.segments
.concat(this.filters)
.concat(this.dateFromStartToEndConditionSql(
// If the same time dimension is passed more than once, no need to build the same
// filter condition again and again. Different granularities don't play role here,
// as rollingWindow.granularity is used for filtering.
uniqDateJoinCondition,
fromRollup,
falseView on GitHub (pinned to 7d981676b3)
Solutions
- Use standard Cube granularities (second, minute, hour, day, week, month, quarter, year) so hierarchies share a common parent.
- Fix misspelled granularity values in the query's timeDimensions.
- If multiple time dimensions are required, align them so one granularity is an ancestor of the other (e.g. day + month), or run separate queries.
- Wrap query building in UserError handling and surface a validation message about granularity compatibility.
Example fix
// before
timeDimensions: [
{ dimension: 'Events.time', dateRange: ['2024-01-01','2024-03-01'], granularity: 'day' },
{ dimension: 'Orders.createdAt', dateRange: ['2024-01-01','2024-03-01'], granularity: 'fortnight' }
]
// after
timeDimensions: [
{ dimension: 'Events.time', dateRange: ['2024-01-01','2024-03-01'], granularity: 'day' },
{ dimension: 'Orders.createdAt', dateRange: ['2024-01-01','2024-03-01'], granularity: 'month' }
] Defensive patterns
Strategy: validation
Validate before calling
const GRANS = ['second','minute','hour','day','week','month','quarter','year'];
function validateGranularities(timeDimensions) {
const gs = timeDimensions.filter(td => td.granularity).map(td => td.granularity);
const bad = gs.filter(g => !GRANS.includes(g));
if (bad.length) throw new Error(`Invalid granularities: ${bad.join(', ')}`);
if (new Set(gs).size > 1) {
// ensure one is an ancestor of the other
const sorted = gs.map(g => GRANS.indexOf(g)).sort((a,b)=>a-b);
if (GRANS[sorted[0]] !== 'day' && GRANS[sorted[0]] !== 'second' && GRANS[sorted[0]] !== 'minute' && GRANS[sorted[0]] !== 'hour' && GRANS[sorted[0]] !== 'week' && GRANS[sorted[0]] !== 'month' && GRANS[sorted[0]] !== 'quarter' && GRANS[sorted[0]] !== 'year') throw new Error('no common parent');
}
} Try / catch
try {
await cubeApi.load(query);
} catch (e) {
if (/Can't find common parent for/.test(e.message)) {
console.error('Use standard granularities so a common parent exists');
}
throw e;
} Prevention
- Only use standard Cube granularities in queries
- Validate timeDimensions granularity values against the allowed enum client-side
- Avoid mixing many different granularities in a single multi-timeDimension query
When it happens
Trigger: Calling overTimeSeriesQuery / minGranularity paths where two time dimensions (or a cumulative measure and a time dimension) have granularities that share no common ancestor — e.g. mixing granularities from different hierarchies or an unknown/invalid granularity value.
Common situations: Passing 'quarter'-style custom or misspelled granularities (e.g. 'week' typo, 'hours' instead of 'hour') in a query with multiple time dimensions, or combining granularities from different cubes whose hierarchies don't overlap.
Related errors
- Data blending query granularities must match
- Data blending query without granularity is not supported
- Can't build query for time dimensions with different date ra
- maskedMembers cannot be provided in the query
- compareDateRange can only exist for one timeDimension
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/cfb483381445a0d7.
Report an issue: GitHub.