{"record":{"id":"13fe7c8af3859e14","repo":"databendlabs/databend","slug":"internal-error-entered-unreachable-code-13fe7c","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/service/src/physical_plans/physical_mutation_manipulate.rs","lineNumber":127,"sourceCode":"    // +----------------------+           |                       +---+                +-----------------------------+\n    //                                    |                       |   | NotMatched     |                             +-+\n    //                                    |                       +---+--------------->| MergeIntoNotMatchedProcessor| |\n    //                                    +-----------------------+                    |                             +-+\n    //                                                                                 +-----------------------------+\n    // Note: here the output_port of MatchedSplitProcessor are arranged in the following order\n    // (0) -> output_port_row_id\n    // (1) -> output_port_updated\n\n    // Outputs from MatchedSplitProcessor's output_port_updated and MergeIntoNotMatchedProcessor's output_port are merged and processed uniformly by the subsequent ResizeProcessor\n    // receive matched data and not matched data parallelly.\n    fn build_pipeline2(&self, builder: &mut PipelineBuilder) -> Result<()> {\n        self.input.build_pipeline(builder)?;\n\n        let (step, need_match, need_unmatch) = match self.strategy {\n            MutationStrategy::MatchedOnly => (1, true, false),\n            MutationStrategy::NotMatchedOnly => (1, false, true),\n            MutationStrategy::MixedMatched => (2, true, true),\n            MutationStrategy::Direct => unreachable!(),\n        };\n\n        let tbl = builder\n            .ctx\n            .build_table_by_table_info(&self.table_info, None)?;\n\n        let input_schema = self.input.output_schema()?;\n        let mut pipe_items = Vec::with_capacity(builder.main_pipeline.output_len());\n        for _ in (0..builder.main_pipeline.output_len()).step_by(step) {\n            if need_match {\n                let matched_split_processor = MatchedSplitProcessor::create(\n                    builder.ctx.clone(),\n                    self.row_id_idx,\n                    self.matched.clone(),\n                    self.field_index_of_input_schema.clone(),\n                    input_schema.clone(),\n                    Arc::new(DataSchema::from(tbl.schema_with_stream())),\n                    false,","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/physical_plans/physical_mutation_manipulate.rs#L109-L145","documentation":"A `unreachable!()` panic in `MutationManipulate::build_pipeline2`. The match maps each `MutationStrategy` to a (step, need_match, need_unmatch) tuple, and `Direct` is asserted impossible. Hitting this panic means a Direct-strategy mutation plan was dispatched to the matched/unmatched pipeline builder, violating the planner's assumption that Direct plans bypass this path entirely.","triggerScenarios":"Executing a MutationManipulate plan with `MutationStrategy::Direct`; the executor calls build_pipeline2 which only supports MatchedOnly, NotMatchedOnly, and MixedMatched strategies.","commonSituations":"MERGE INTO workloads after a planner/executor version skew; queries where the optimizer recently started classifying plans as Direct but the manipulate-stage builder predates that change.","solutions":["Report the failing MERGE INTO query and plan to Databend maintainers — this is an internal invariant violation","Upgrade to the newest Databend release to pick up fixes for Direct-strategy mutation handling","Trace plan construction to find why a Direct-strategy plan entered the manipulate builder instead of the Direct fast path","Rewrite the MERGE INTO statement so the optimizer produces a MatchedOnly/MixedMatched/NotMatchedOnly strategy"],"exampleFix":"// before\nMutationStrategy::MixedMatched => (2, true, true),\nMutationStrategy::Direct => unreachable!(),\n// after\nMutationStrategy::MixedMatched => (2, true, true),\nMutationStrategy::Direct => (0, false, false), // Direct strategy bypasses match/unmatch pipelines","handlingStrategy":"try-catch","validationCode":"if matches!(plan.strategy, MutationStrategy::Direct) {\n    return Err(ErrorCode::Internal(\"Direct strategy not supported in MutationManipulate\"));\n}","typeGuard":"fn is_direct_strategy(s: &MutationStrategy) -> bool { matches!(s, MutationStrategy::Direct) }","tryCatchPattern":"catch_unwind around build_pipeline2; map panic to ErrorCode::Internal with the query id attached","preventionTips":["Route Direct-strategy mutation plans to their dedicated executor path before build_pipeline2","Add exhaustive-match tests for MutationStrategy in every mutation plan builder","Fail fast at plan construction if strategy and plan type are incompatible","Prefer returning ErrorCode over unreachable!() for user-reachable states"],"tags":["rust","panic","unreachable","internal-invariant","merge-into","physical-plan"],"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"}