risingwavelabs/risingwave · error · BatchError

Join key types are not aligned: LHS: {outer_type:?}, RHS: {i

Error message

Join key types are not aligned: LHS: {outer_type:?}, RHS: {inner_type:?}

What it means

Identical check to the distributed lookup join: when the local lookup join builds a scan range over the inner table, each outer join-key Datum's type must exactly equal the inner-side key column type, otherwise the datum is rejected with a message naming the mismatched LHS/RHS types.

Source

Thrown at src/batch/executors/src/executor/join/local_lookup_join.rs:189

        let mut scan_range = ScanRange::full_table_scan();

        for ((datum, outer_type), inner_type) in key_datums
            .into_iter()
            .zip_eq_fast(
                self.outer_side_key_types
                    .iter()
                    .take(self.lookup_prefix_len),
            )
            .zip_eq_fast(
                self.inner_side_key_types
                    .iter()
                    .take(self.lookup_prefix_len),
            )
        {
            let datum = if inner_type == outer_type {
                datum
            } else {
                bail!("Join key types are not aligned: LHS: {outer_type:?}, RHS: {inner_type:?}");
            };

            scan_range.eq_conds.push(datum);
        }

        let vnode = self.get_virtual_node(&scan_range)?;
        let worker_slot_id = self.vnode_mapping[vnode.to_index()];

        let list = self
            .worker_slot_to_scan_range_mapping
            .entry(worker_slot_id)
            .or_default();
        list.push((scan_range, vnode));

        Ok(())
    }

    /// Builds and returns the `ExchangeExecutor` used for the inner side of the

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Re-plan/re-run the query so it picks up the current inner table schema
  2. Align the inner table column types with the outer join key types (recreate or refresh the table/MV)
  3. Add explicit casts in the SQL so both join key sides share the same type

Example fix

// before
SELECT * FROM orders o JOIN dim ON o.dim_id = dim.id; -- int vs bigint keys
// after
SELECT * FROM orders o JOIN dim ON o.dim_id::bigint = dim.id;
Defensive patterns

Strategy: validation

Validate before calling

fn keys_aligned(outer_types: &[DataType], inner_types: &[DataType]) -> bool {
    outer_types.len() == inner_types.len()
        && outer_types.iter().zip(inner_types).all(|(o, i)| o == i)
}

Try / catch

match executor_result {
    Err(e) if e.to_string().contains("Join key types are not aligned") => {
        // re-plan against the current table schema, or add explicit casts, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: add_scan_range on LocalLookupJoinExecutor receives outer key datums whose DataType differs from the inner table key column types — e.g. inner table column type changed after the plan was built, or key types differ across join sides without a cast.

Common situations: Schema drift on the lookup table (ALTER/refresh) while a query plan is still active; plans generated before a type-coercion change in the frontend; query against a materialized view whose key types differ from the outer relation.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/ae89a66715aa5a77. Report an issue: GitHub.