cube-js/cube · error · UserError
Members ${invalidMembers.join(', ')} in join from '${j.origi
Error message
Members ${invalidMembers.join(', ')} in join from '${j.originalFrom}' to '${j.originalTo}' doesn't reference join cubes What it means
Cube validates that every member referenced inside a rollupJoin's join SQL belongs to one of the cubes participating in the join chain. Members whose cube prefix is neither a join cube nor the join's 'to' cube are collected as invalidMembers and this UserError is thrown. It protects against typos or wrong-cube references in join conditions.
Source
Thrown at packages/cubejs-schema-compiler/src/adapter/PreAggregations.ts:1119
if (fromPreAggObj.length > 1) {
throw new UserError(
`Multiple rollups found that can be used for rollup join ${JSON.stringify(join)}: ${fromPreAggObj.map(p => this.preAggregationId(p)).join(', ')}`,
);
}
return fromPreAggObj[0];
}
private resolveJoinMembers(join: FinishedJoinTree): JoinEdgeWithMembers[] {
const joinMap = new Set<string>();
return join.joins.map(j => {
joinMap.add(j.originalFrom);
const memberPaths = this.query.collectMemberNamesFor(() => this.query.evaluateSql(j.originalFrom, j.join.sql)).map(m => m.split('.'));
const invalidMembers = memberPaths.filter(m => !joinMap.has(m[0]) && m[0] !== j.originalTo);
if (invalidMembers.length) {
throw new UserError(`Members ${invalidMembers.join(', ')} in join from '${j.originalFrom}' to '${j.originalTo}' doesn't reference join cubes`);
}
const fromMembers = memberPaths.filter(m => joinMap.has(m[0])).map(m => m.join('.'));
if (!fromMembers.length) {
throw new UserError(`From members are not found in [${memberPaths.map(m => m.join('.')).join(', ')}] for join ${JSON.stringify(j)}. Please make sure join fields are referencing dimensions instead of columns.`);
}
const toMembers = memberPaths.filter(m => m[0] === j.originalTo).map(m => m.join('.'));
if (!toMembers.length) {
throw new UserError(`To members are not found in [${memberPaths.map(m => m.join('.')).join(', ')}] for join ${JSON.stringify(j)}. Please make sure join fields are referencing dimensions instead of columns.`);
}
joinMap.add(j.originalTo);
return {
...j,
fromMembers,
toMembers,
};
});
}View on GitHub (pinned to 7d981676b3)
Solutions
- Fix the join sql so every member uses a prefix matching either the join's from cube or the to cube (e.g. '${Orders}.id = ${Customers}.orders_id').
- Add the referenced cube to the join chain if it genuinely participates in the relationship.
- Correct typos in cube names inside the join sql.
Example fix
// before
join: { sql: '${CUBE}.customer_id = ${Geo.customer}.id' } // Geo not in join
// after
join: { sql: '${CUBE}.customer_id = ${Customers}.id' } Defensive patterns
Strategy: validation
Validate before calling
// Validate that every '${Cube}.member' in a join sql references only the join's cubes
function validateJoinCubes(joinSql, allowedCubes) {
const refs = [...joinSql.matchAll(/\$\{([A-Za-z0-9_]+)\./g)].map(m => m[1]);
const bad = refs.filter(c => !allowedCubes.includes(c));
if (bad.length) throw new Error(`Join references cubes not in join: ${[...new Set(bad)].join(', ')}`);
} Type guard
function joinUsesOnlyCubes(join, cubes) { return collectMemberNames(join.sql).every(name => cubes.includes(name.split('.')[0])); } Try / catch
try { await cube.query(query); } catch (e) { if (/doesn't reference join cubes/.test(e.message)) { console.error('Join SQL references a cube outside the join chain:', e.message); } else throw e; } Prevention
- Only use ${Cube}.dimension references in join sql, never raw columns
- Double-check cube prefixes when copying joins between cubes
- Keep join definitions next to their cubes so prefixes are obvious
- Run schema compile in CI to catch invalid join members before deploy
When it happens
Trigger: A join's sql expression references a member like 'OtherCube.someDimension' where OtherCube is not in the join map (not originalFrom, not a prior join cube, and not originalTo), evaluated via collectMemberNamesFor + evaluateSql during rollupJoin processing.
Common situations: Copy-pasting a join SQL from another cube and forgetting to update the cube prefix; referencing a dimension from an unrelated cube in the ON condition; typos in cube names so the prefix doesn't match the join's cubes.
Related errors
- From members are not found in [${memberPaths.map(m => m.join
- To members are not found in [${memberPaths.map(m => m.join('
- Can't build join tree for pre-aggregation ${preAggObj.cube}.
- Nothing to join in rollup join. Target joins ${JSON.stringif
- No rollups found that can be used for a rollup join from "${
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/f6394ae2cfc3a8b7.
Report an issue: GitHub.