{"record":{"id":"8e7bf4884e784f8e","repo":"databendlabs/databend","slug":"plan-in-insertinputsource-stag-must-be-copyintota","errorCode":null,"errorMessage":"plan in InsertInputSource::Stag must be CopyIntoTable","messagePattern":"plan in InsertInputSource::Stag must be CopyIntoTable","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/service/src/interpreters/interpreter_replace.rs","lineNumber":444,"sourceCode":"                    let (physical_plan, _, _) = interpreter\n                        .build_physical_plan(_table_info, &copy_plan, _table_meta_timestamps)\n                        .await?;\n\n                    // TODO optimization: if copy_plan.stage_table_info.files_to_copy is None, there should be a short-cut plan\n\n                    *_purge_info = Some((\n                        copy_plan.stage_table_info.files_to_copy.unwrap_or_default(),\n                        copy_plan.stage_table_info.stage_info.clone(),\n                        copy_plan.stage_table_info.copy_into_table_options.clone(),\n                    ));\n                    Ok(ReplaceSourceCtx {\n                        root: physical_plan,\n                        select_ctx: None,\n                        update_stream_meta: vec![],\n                        bind_context: None,\n                    })\n                }\n                _ => unreachable!(\"plan in InsertInputSource::Stag must be CopyIntoTable\"),\n            },\n            #[cfg(not(feature = \"storage-stage\"))]\n            InsertInputSource::Stage(_) => Err(ErrorCode::Unimplemented(\n                \"Stage COPY source support is disabled, rebuild with cargo feature 'storage-stage'\",\n            )),\n            InsertInputSource::StreamingLoad { .. } => {\n                unreachable!(\"replace with streaming not supported yet\")\n            }\n        }\n    }\n\n    fn connect_value_source(\n        &self,\n        schema: DataSchemaRef,\n        source: &InsertValue,\n    ) -> Result<PhysicalPlan> {\n        Ok(PhysicalPlan::new(ReplaceAsyncSourcer {\n            schema,","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/interpreters/interpreter_replace.rs#L426-L462","documentation":"connect_input_source in the REPLACE interpreter handles each InsertInputSource variant. When the source is InsertInputSource::Stage (with the storage-stage feature enabled), the embedded plan must specifically be a CopyIntoTable physical plan; any other plan type there violates the invariant and panics via unreachable!.","triggerScenarios":"Executing REPLACE ... with a stage-based input source where the physical plan stored in InsertInputSource::Stage is not CopyIntoTable — e.g. the planner produced a different stage-read plan for REPLACE.","commonSituations":"Building Databend with the 'storage-stage' feature and issuing REPLACE INTO ... FROM @stage; planner changes that wrap or alter the stage COPY plan before REPLACE execution.","solutions":["Inspect the REPLACE statement's stage source and confirm the planner emits CopyIntoTable for it.","Upgrade to a build where the REPLACE planner produces CopyIntoTable for stage sources.","Avoid REPLACE INTO ... FROM @stage; stage the data into a table first, then use REPLACE with a query source."],"exampleFix":"// before\n_ => unreachable!(\"plan in InsertInputSource::Stag must be CopyIntoTable\"),\n// after\nother => Err(ErrorCode::Internal(format!(\n    \"REPLACE stage source expects CopyIntoTable plan, got {:?}\", other\n))),","handlingStrategy":"validation","validationCode":"// Ensure REPLACE uses a query source, not a stage/stream source\nlet src = match &insert_plan.input_source {\n    InsertInputSource::SelectPlan(_) => Ok(()),\n    _ => Err(\"REPLACE only supports SELECT sources here\"),\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't combine REPLACE with stage COPY or streaming sources","Test REPLACE statements against the planner output in CI","Stage data into a table first, then REPLACE from that table"],"tags":["rust","unreachable","stage","copy-into"],"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"}