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

  1. 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').
  2. Add the referenced cube to the join chain if it genuinely participates in the relationship.
  3. 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

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


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/f6394ae2cfc3a8b7. Report an issue: GitHub.