cube-js/cube · error · UserError

To join across data sources use rollupJoin with Cube Store.

Error message

To join across data sources use rollupJoin with Cube Store. If rollupJoin is defined, this error indicates it doesn't match the query. Please use Rollup Designer to verify it's definition. Found data sources: ${dataSources.join(', ')}

What it means

The query's dataSource getter collects the distinct data sources of all cubes involved. If more than one data source is found and the query is not an external (rollupJoin) pre-aggregation query, Cube cannot execute it on a single connection and throws, telling you rollupJoin with Cube Store is required for cross-source joins.

Source

Thrown at packages/cubejs-schema-compiler/src/adapter/BaseQuery.js:594

      if (Array.isArray(hint)) {
        return hint;
      }

      for (const path of allPaths) {
        const hintIndex = path.indexOf(hint);
        if (hintIndex !== -1) {
          return path.slice(0, hintIndex + 1);
        }
      }

      return hint;
    });
  }

  get dataSource() {
    const dataSources = R.uniq(this.allCubeNames.map(c => this.cubeDataSource(c)));
    if (dataSources.length > 1 && !this.externalPreAggregationQuery()) {
      throw new UserError(`To join across data sources use rollupJoin with Cube Store. If rollupJoin is defined, this error indicates it doesn't match the query. Please use Rollup Designer to verify it's definition. Found data sources: ${dataSources.join(', ')}`);
    }
    return dataSources[0];
  }

  cubeDataSource(cube) {
    return this.cubeEvaluator.cubeFromPath(cube).dataSource || 'default';
  }

  get aliasNameToMember() {
    return R.fromPairs(
      this.measures.map(m => [m.unescapedAliasName(), m.measure]).concat(
        this.dimensions.map(m => [m.unescapedAliasName(), m.dimension])
      ).concat(
        this.timeDimensions.filter(m => !!m.granularity)
          .map(m => [m.unescapedAliasName(), `${m.dimension}.${m.granularity}`])
      )
    );
  }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Restrict the query to cubes sharing the same dataSource
  2. Define a correct rollupJoin pre-aggregation and ensure external pre-agigrations/Cube Store are enabled
  3. Set the dataSource property explicitly on every cube so they align
  4. Use the Rollup Designer to verify the rollupJoin definition matches the query

Example fix

// before (cube in another DB, no rollupJoin)
cube: `FinanceBudget`, sql: `SELECT * FROM budget_db.budget`
// after
cube: `FinanceBudget`, sql: `SELECT * FROM budget_db.budget`, dataSource: 'budget',
rollups: { /* rollupJoin matching the queried members via Cube Store */ }
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: ensure all queried cubes share one dataSource (client-side meta check)
const sources = new Set(queryMembers.map(m => dataSourceOfCube(m.split('.')[0])));
if (sources.size > 1 && !hasMatchingRollupJoin(query)) {
  throw new Error(`Cross-source query needs rollupJoin: ${[...sources].join(', ')}`);
}

Try / catch

try {
  return await cubeApi.load(query);
} catch (e) {
  if (/To join across data sources/.test(e.message)) {
    const sources = /Found data sources: (.+)$/.exec(e.message)?.[1];
    throw new Error(`Restrict query to one data source or define rollupJoin (found: ${sources})`);
  }
  throw e;
}

Prevention

When it happens

Trigger: A query combining members from cubes with different 'dataSource' values (e.g. 'default' and 'warehouseB') without a matching rollupJoin pre-aggregation, or with externalPreAggregationQuery() false.

Common situations: Federating tables from two databases (e.g. Postgres + BigQuery) in one query, forgetting to set dataSource on a new cube so it defaults differently, or a rollupJoin definition that doesn't match the query's members.

Related errors


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