{"record":{"id":"178086aa745c0f90","repo":"cube-js/cube","slug":"unexpected-join-node","errorCode":null,"errorMessage":"Unexpected join node: {:?}","messagePattern":"Unexpected join node: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust/cubesql/cubesql/src/compile/rewrite/converter.rs","lineNumber":2193,"sourceCode":"                        .collect::<Result<Vec<_>, CubeError>>()?;\n                let group_expr =\n                    match_expr_list_node!(node_by_id, to_expr, params[3], WrappedSelectGroupExpr);\n                let aggr_expr =\n                    match_expr_list_node!(node_by_id, to_expr, params[4], WrappedSelectAggrExpr);\n                let window_expr =\n                    match_expr_list_node!(node_by_id, to_expr, params[5], WrappedSelectWindowExpr);\n                let from = Arc::new(self.to_logical_plan(params[6])?);\n                let joins = match_list_node!(node_by_id, params[7], WrappedSelectJoins)\n                    .into_iter()\n                    .map(|j| {\n                        if let LogicalPlanLanguage::WrappedSelectJoin(params) = j {\n                            let input = Arc::new(self.to_logical_plan(params[0])?);\n                            let join_expr = to_expr(params[1])?;\n                            let join_type =\n                                match_data_node!(node_by_id, params[2], WrappedSelectJoinJoinType);\n                            Ok((input, join_expr, join_type))\n                        } else {\n                            panic!(\"Unexpected join node: {:?}\", j)\n                        }\n                    })\n                    .collect::<Result<Vec<_>, _>>()?;\n\n                let filter_expr =\n                    match_expr_list_node!(node_by_id, to_expr, params[8], WrappedSelectFilterExpr);\n                let having_expr =\n                    match_expr_list_node!(node_by_id, to_expr, params[9], WrappedSelectHavingExpr);\n                let limit = match_data_node!(node_by_id, params[10], WrappedSelectLimit);\n                let offset = match_data_node!(node_by_id, params[11], WrappedSelectOffset);\n                let order_expr =\n                    match_expr_list_node!(node_by_id, to_expr, params[12], WrappedSelectOrderExpr);\n                let alias = match_data_node!(node_by_id, params[13], WrappedSelectAlias);\n                let distinct = match_data_node!(node_by_id, params[14], WrappedSelectDistinct);\n                let push_to_cube =\n                    match_data_node!(node_by_id, params[15], WrappedSelectPushToCube);\n\n                let filter_expr = normalize_cols(","sourceCodeStart":2175,"sourceCodeEnd":2211,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/rust/cubesql/cubesql/src/compile/rewrite/converter.rs#L2175-L2211","documentation":"to_logical_plan builds joins from select IR nodes; each join input must be a recognized join-language node. When a join operand node has an unexpected shape, the converter panics with 'Unexpected join node' and the debug dump of the node.","triggerScenarios":"A SELECT with a JOIN whose operand (input, join expression, or join type) doesn't match the expected LogicalPlanLanguage variants — e.g. exotic join types (lateral, asymmetric), complex join conditions, or joins on unsupported constructs.","commonSituations":"SQL API queries using JOIN types/conditions CubeSQL's planner can't model (FULL OUTER with complex ON, LATERAL joins, subquery joins in unusual positions); older drivers emitting legacy join syntax.","solutions":["Rewrite the join using standard INNER/LEFT joins with simple ON conditions","Replace subquery-in-join patterns with CTEs and join those","Upgrade CubeSQL; if reproducible with plain SQL, file an issue with the dumped node"],"exampleFix":"// before\nSELECT ... FROM a, LATERAL (SELECT ...) b\n// after\nWITH b AS (SELECT ...) SELECT ... FROM a JOIN b ON ...","handlingStrategy":"try-catch","validationCode":"// Reject join shapes known to fail conversion before sending\nfn validate_joins(stmt: &SqlStatement) -> Result<(), String> {\n    for j in stmt.joins() {\n        if matches!(j.kind, JoinKind::Lateral | JoinKind::Asymmetric | JoinKind::CrossApply) {\n            return Err(format!(\"join kind {:?} may not be supported\", j.kind));\n        }\n        if j.on_condition().contains_subquery() { return Err(\"subqueries in ON clauses are unsupported\".into()); }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"let res = std::panic::catch_unwind(AssertUnwindSafe(|| planner.plan(sql)));\nif res.is_err() {\n    // surface 'Unexpected join node' as a 4xx with guidance to simplify the join\n    return bad_request(\"Query uses a join shape the planner cannot convert; rewrite with standard INNER/LEFT joins\");\n}","preventionTips":["Prefer INNER/LEFT joins with simple ON conditions","Express lateral/correlated joins as CTEs joined on explicit keys","Avoid subqueries inside join conditions"],"tags":["rust","panic","join","sql-compilation"],"backgroundTag":"unsupported-join-node","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}