Skip to content

rollup_join not matched when query includes a measure from the secondary (right-side) cube, despite that measure being explicitly listed in the rollup_join definition #11124

Description

@udit-pandey

Describe the bug
A rollup_join pre-aggregation that explicitly includes measures from both the primary and secondary cube fails to be matched when the query contains a measure originating from the secondary cube. Cube.js throws a cross-data-source error as if no matching rollup_join exists, even though the measure is explicitly declared in the rollup_join's measures array.

Error: 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: secondary, default

The error also surfaces via RefreshScheduler (not just at query time), despite the rollup_join being correctly defined to handle the cross-data-source case.

To Reproduce
Steps to reproduce the behavior:

  1. Configure two data sources in cube.jsdefault (standard PostgreSQL) and secondary (a second PostgreSQL instance)
  2. Define PrimaryCube on the default data source with a main rollup pre-aggregation that includes a sum measure and an ID dimension (for join) and a location dimension
  3. Define SecondaryCube on the secondary data source with a base rollup pre-aggregation, and a rollup_join pre-aggregation that explicitly lists measures from both cubes and dimensions from both cubes
  4. Start the Cube.js service and wait for pre-aggregations to build
  5. Run Query A — measures only from PrimaryCube, dimension from SecondaryCubesucceeds
  6. Add a measure from SecondaryCube to the same query (Query B) → throws cross-data-source error

Expected behavior
The Cube.js service should start up cleanly without throwing cross-data-source errors during the pre-aggregation refresh cycle.

Both Query A and Query B should be served by the rollup_join pre-aggregation. Query B is a strict subset of the rollup_join's declared measures and dimensions arrays — Cube.js should recognise it as a match and route accordingly, exactly as it does for Query A.

Screenshots
Error text:

Error: 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: secondary, default

Minimally reproducible Cube Schema
Two data sources must be configured in cube.jsdefault and secondary.

// SecondaryCube — uses 'secondary' data source
cube(`SecondaryCube`, {
  data_source: `secondary`,
  sql: `
    select 1 as id, 'loc_1' as location_id, 500 as contract_value
    UNION ALL
    select 2 as id, 'loc_2' as location_id, 300 as contract_value
  `,

  dimensions: {
    id: { sql: `id`, type: `string`, primary_key: true },
    location_id: { sql: `location_id`, type: `string` }
  },

  measures: {
    total_contract_value: {
      sql: `contract_value`,
      type: `sum`
    }
  },

  preAggregations: {
    main: {
      type: `rollup`,
      external: true,
      measures: [CUBE.total_contract_value],
      dimensions: [CUBE.id, CUBE.location_id],
      granularity: `day`
    }
  }
});

// PrimaryCube — uses 'default' data source
cube(`PrimaryCube`, {

  sql: `
    select 1 as id, 1 as secondary_id, 'SUCCESS' as action_status
    UNION ALL
    select 2 as id, 2 as secondary_id, 'SUCCESS' as action_status
    UNION ALL
    select 3 as id, 1 as secondary_id, 'FAILURE' as action_status
  `,

  joins: {
    SecondaryCube: {
      sql: `${CUBE}.secondary_id = ${SecondaryCube}.id`,
      relationship: `many_to_one`
    }
  },

  dimensions: {
    id: { sql: `id`, type: `string`, primary_key: true },
    secondary_id: { sql: `secondary_id`, type: `string` },
    action_status: { sql: `action_status`, type: `string` }
  },

  measures: {
    total_count: {
      type: `count`,
      filters: [{ sql: `${CUBE}.action_status = 'SUCCESS'` }]
    }
  },

  preAggregations: {
    primary_rollup: {
      type: `rollup`,
      external: true,
      measures: [CUBE.total_count],
      dimensions: [CUBE.secondary_id, CUBE.action_status],
      granularity: `day`
    },

    joined_rollup: {
      type: `rollup_join`,
      rollups: [PrimaryCube.primary_rollup, SecondaryCube.main],
      measures: [
        PrimaryCube.total_count,
        SecondaryCube.total_contract_value  // ← secondary measure, explicitly listed
      ],
      dimensions: [
        PrimaryCube.secondary_id,
        SecondaryCube.location_id           // ← secondary dimension, explicitly listed
      ],
      granularity: `day`
    }
  }
});

Query A — succeeds (measure from primary only, dimension from secondary):

{
  "measures": ["PrimaryCube.total_count"],
  "dimensions": ["SecondaryCube.location_id"]
}

Query B — fails (adds a measure from the secondary cube):

{
  "measures": ["PrimaryCube.total_count", "SecondaryCube.total_contract_value"],
  "dimensions": ["SecondaryCube.location_id"]
}

Version:
1.3.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions