{"record":{"id":"e0759067697b9a9d","repo":"databendlabs/databend","slug":"internal-error-entered-unreachable-code-e07590","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/plans/plan.rs","lineNumber":739,"sourceCode":"    pub fn bind_context(&self) -> Option<BindContext> {\n        if let Plan::Query { bind_context, .. } = self {\n            Some(*bind_context.clone())\n        } else {\n            None\n        }\n    }\n\n    pub fn replace_query_s_expr(&self, s_expr: SExpr) -> Self {\n        let Plan::Query {\n            metadata,\n            bind_context,\n            rewrite_kind,\n            formatted_ast,\n            ignore_result,\n            ..\n        } = self\n        else {\n            unreachable!()\n        };\n\n        Plan::Query {\n            s_expr: Box::new(s_expr),\n            metadata: metadata.clone(),\n            bind_context: bind_context.clone(),\n            rewrite_kind: rewrite_kind.clone(),\n            formatted_ast: formatted_ast.clone(),\n            ignore_result: *ignore_result,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]","sourceCodeStart":721,"sourceCodeEnd":757,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/sql/src/planner/plans/plan.rs#L721-L757","documentation":"replace_query_s_expr destructures self with a let-else expecting the Plan::Query variant; any other Plan variant hits `unreachable!()`. The function is public but is only meant to be called on query plans (rewriting the s_expr of a bound SELECT), so callers passing Explain/Insert/DDL plans violate the function's contract and panic.","triggerScenarios":"Calling Plan::replace_query_s_expr on a non-Query plan — e.g. invoking it from a rewrite pass that also handles EXPLAIN, INSERT, or catalog plans without checking the variant first.","commonSituations":"Hit by internal optimizer passes that rewrite materialized-view or query plans and forget to filter to Plan::Query; users see it as an internal error during query preparation.","solutions":["Guard call sites: only invoke replace_query_s_expr after matching Plan::Query.","Replace the let-else `unreachable!()` with returning an error (e.g. ErrorCode::Internal) naming the received plan variant.","Consider making the method take a Query plan by construction to eliminate the bad call shape.","Add a debug log of the plan variant before the destructure when debugging."],"exampleFix":"// before\n} else {\n    unreachable!()\n};\n// after\n} else {\n    return Err(ErrorCode::Internal(\"replace_query_s_expr called on non-Query plan\"));\n};","handlingStrategy":"type-guard","validationCode":"// In Rust call sites, narrow before calling:\nif let Plan::Query { .. } = &plan {\n    let new_plan = plan.replace_query_s_expr(s_expr, metadata, bind_context, ...)?;\n}","typeGuard":"fn is_query_plan(p: &Plan) -> bool { matches!(p, Plan::Query { .. }) }","tryCatchPattern":null,"preventionTips":["Never call replace_query_s_expr on EXPLAIN/INSERT/DDL plans; filter to Plan::Query first.","Prefer internal helpers that take the Query variant directly.","Search call sites with type guards when refactoring Plan enums.","Add a compile-time variant-specific API to eliminate the panic path."],"tags":["rust","planner","panic","public-api"],"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"}