{"record":{"id":"ae89a66715aa5a77","repo":"risingwavelabs/risingwave","slug":"join-key-types-are-not-aligned-lhs-outer-type-ae89a6","errorCode":null,"errorMessage":"Join key types are not aligned: LHS: {outer_type:?}, RHS: {inner_type:?}","messagePattern":"Join key types are not aligned: LHS: (.+?), RHS: (.+?)","errorType":"exception","errorClass":"BatchError","httpStatus":null,"severity":"error","filePath":"src/batch/executors/src/executor/join/local_lookup_join.rs","lineNumber":189,"sourceCode":"        let mut scan_range = ScanRange::full_table_scan();\n\n        for ((datum, outer_type), inner_type) in key_datums\n            .into_iter()\n            .zip_eq_fast(\n                self.outer_side_key_types\n                    .iter()\n                    .take(self.lookup_prefix_len),\n            )\n            .zip_eq_fast(\n                self.inner_side_key_types\n                    .iter()\n                    .take(self.lookup_prefix_len),\n            )\n        {\n            let datum = if inner_type == outer_type {\n                datum\n            } else {\n                bail!(\"Join key types are not aligned: LHS: {outer_type:?}, RHS: {inner_type:?}\");\n            };\n\n            scan_range.eq_conds.push(datum);\n        }\n\n        let vnode = self.get_virtual_node(&scan_range)?;\n        let worker_slot_id = self.vnode_mapping[vnode.to_index()];\n\n        let list = self\n            .worker_slot_to_scan_range_mapping\n            .entry(worker_slot_id)\n            .or_default();\n        list.push((scan_range, vnode));\n\n        Ok(())\n    }\n\n    /// Builds and returns the `ExchangeExecutor` used for the inner side of the","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/batch/executors/src/executor/join/local_lookup_join.rs#L171-L207","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-plan/re-run the query so it picks up the current inner table schema","Align the inner table column types with the outer join key types (recreate or refresh the table/MV)","Add explicit casts in the SQL so both join key sides share the same type"],"exampleFix":"// before\nSELECT * FROM orders o JOIN dim ON o.dim_id = dim.id; -- int vs bigint keys\n// after\nSELECT * FROM orders o JOIN dim ON o.dim_id::bigint = dim.id;","handlingStrategy":"validation","validationCode":"fn keys_aligned(outer_types: &[DataType], inner_types: &[DataType]) -> bool {\n    outer_types.len() == inner_types.len()\n        && outer_types.iter().zip(inner_types).all(|(o, i)| o == i)\n}","typeGuard":null,"tryCatchPattern":"match executor_result {\n    Err(e) if e.to_string().contains(\"Join key types are not aligned\") => {\n        // re-plan against the current table schema, or add explicit casts, then retry\n    }\n    other => other?,\n}","preventionTips":["Cast join keys explicitly in SQL so both sides share a type before lookup","Re-plan queries after any ALTER or schema refresh on the lookup table","Add a planner-level check that local lookup join key types are identical on both sides"],"tags":["rust","lookup-join","type-mismatch","schema"],"backgroundTag":"type-mismatch","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}