{"record":{"id":"a8486d631b9f5519","repo":"databendlabs/databend","slug":"internal-error-entered-unreachable-code-a8486d","errorCode":null,"errorMessage":"internal error: entered unreachable code","messagePattern":"internal error: entered unreachable code","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/sql/src/planner/optimizer/optimizers/rule/join_rules/push_down_filter_join/outer_join_to_anti_join.rs","lineNumber":61,"sourceCode":"    let join_expr = s_expr.unary_child();\n    let join = join_expr.plan().as_join().unwrap();\n    let anti_join_type = match join.join_type {\n        JoinType::Left => JoinType::LeftAnti,\n        JoinType::Right => JoinType::RightAnti,\n        _ => return Ok(None),\n    };\n\n    let Some(predicate_index) = filter.predicates.iter().position(|predicate| {\n        let Some(null_tested_expr) = null_tested_expr(predicate) else {\n            return false;\n        };\n\n        join.equi_conditions.iter().any(|condition| {\n            !condition.is_null_equal\n                && match join.join_type {\n                    JoinType::Left => condition.right == *null_tested_expr,\n                    JoinType::Right => condition.left == *null_tested_expr,\n                    _ => unreachable!(),\n                }\n        })\n    }) else {\n        return Ok(None);\n    };\n\n    // An anti join outputs only its preserved side, while the original\n    // outer-join/filter shape still exposes the other side as NULL. Recreate\n    // those symbols so upper operators preserve their schema.\n    let null_extended_prop = match join.join_type {\n        JoinType::Left => join_expr.right_child().derive_relational_prop()?,\n        JoinType::Right => join_expr.left_child().derive_relational_prop()?,\n        _ => unreachable!(),\n    };\n    let metadata = metadata.read();\n    let null_items = null_extended_prop\n        .output_columns\n        .iter()","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/sql/src/planner/optimizer/optimizers/rule/join_rules/push_down_filter_join/outer_join_to_anti_join.rs#L43-L79","documentation":"Inside outer_join_to_anti_join, the null-tested equi-condition check matches on JoinType::Left and JoinType::Right only; any other join type (e.g. Full/Semi/Mark) inside the matched condition hits `unreachable!()`. The enclosing logic is supposed to only run this check on plain outer joins, so this panic means an unexpected join type reached the condition scan.","triggerScenarios":"A filter-over-outer-join pattern being converted to anti join where the join_type is no longer Left/Right at the point of the equi_conditions check — e.g. after another rule mutated join_type, or the rule's eligibility pre-check missed a join kind.","commonSituations":"Seen when optimizing queries like SELECT ... FROM a LEFT JOIN b ... WHERE b.x IS NULL after optimizer refactors; surfaces as an internal error panic during planning.","solutions":["Confirm the rule's matcher only fires for Left/Right outer joins with a NULL-test filter on the non-preserved side.","Inspect the S-expression right before the panic to see the actual join_type.","Make the match defensive: return false for unexpected join types inside the closure instead of panicking.","Re-run the failing query on a recent build to check whether a known optimizer fix already covers it."],"exampleFix":"// before\n_ => unreachable!(),\n// after\n_ => false,","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Catch at query execution layer and fall back to a rewritten query\nmatch run(query) {\n    Err(e) if is_internal_planner_error(&e) => run(rewrite_anti_join_manually(query)),\n    r => r,\n}","preventionTips":["Prefer writing NOT EXISTS with an explicit join instead of LEFT JOIN ... WHERE right IS NULL anti-join idioms.","Keep outer-join + IS NULL filter patterns simple so rule eligibility checks are exercised less.","Upgrade once the optimizer fix for outer-join-to-anti-join lands.","Run EXPLAIN RAW on affected queries in staging before production deploys."],"tags":["rust","optimizer","join","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}