{"record":{"id":"6af69ef70cc8d4b3","repo":"databendlabs/databend","slug":"input-plan-must-be-query-but-it-s-6af69e","errorCode":null,"errorMessage":"Input plan must be Query, but it's {}","messagePattern":"Input plan must be Query, but it's (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/service/src/interpreters/interpreter_copy_into_table.rs","lineNumber":216,"sourceCode":"    /// Create a CopyInterpreter with context and [`CopyIntoTablePlan`].\n    pub fn try_create(ctx: Arc<QueryContext>, plan: CopyIntoTablePlan) -> Result<Self> {\n        Ok(CopyIntoTableInterpreter { ctx, plan })\n    }\n\n    #[async_backtrace::framed]\n    async fn build_query(\n        &self,\n        query: &Plan,\n    ) -> Result<(SelectInterpreter, Vec<UpdateStreamMetaReq>)> {\n        let (s_expr, metadata, bind_context, formatted_ast) = match query {\n            Plan::Query {\n                s_expr,\n                metadata,\n                bind_context,\n                formatted_ast,\n                ..\n            } => (s_expr, metadata, bind_context, formatted_ast),\n            v => unreachable!(\"Input plan must be Query, but it's {}\", v),\n        };\n\n        let update_stream_meta = dml_build_update_stream_req(self.ctx.clone()).await?;\n\n        let select_interpreter = SelectInterpreter::try_create(\n            self.ctx.clone(),\n            *(bind_context.clone()),\n            *s_expr.clone(),\n            metadata.clone(),\n            formatted_ast.clone(),\n            false,\n        )?;\n\n        Ok((select_interpreter, update_stream_meta))\n    }\n\n    #[async_backtrace::framed]\n    pub async fn build_physical_plan(","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/interpreters/interpreter_copy_into_table.rs#L198-L234","documentation":"build_query in interpreter_copy_into_table (src/query/service/src/interpreters/interpreter_copy_into_table.rs:216) destructures the bound plan expecting Plan::Query to build a SelectInterpreter; any other variant hits unreachable!(\"Input plan must be Query, but it's {}\"). COPY INTO <table> requires its source to be a query plan; a non-query plan here is an internal invariant violation.","triggerScenarios":"Executing COPY INTO <table> FROM ... where the bound source plan is not Plan::Query — e.g. a stage/table source form the binder no longer wraps in a query plan, or a planner refactor emitting a different variant reached build_physical_plan -> build_query.","commonSituations":"COPY INTO a table from a stage with a source form that binds unexpectedly; statements copied from older Databend syntax after an upgrade changed binder output; internal regressions where Explain or DML wrapper plans leak into the copy path.","solutions":["Rewrite the COPY INTO source as an explicit SELECT: `COPY INTO target FROM (SELECT ... FROM @stage ...)`","Upgrade to a version where the copy-into-table binder guarantees a Query plan or raises a clear user error","If already using SELECT, file a bug with the exact SQL and Databend version","As a code fix, replace unreachable! with a returned ErrorCode::Internal naming the unexpected variant"],"exampleFix":"// before\nlet (s_expr, metadata, bind_context, formatted_ast) = match plan {\n    Plan::Query { s_expr, metadata, bind_context, formatted_ast, .. } => (...),\n    v => unreachable!(\"Input plan must be Query, but it's {}\", v),\n};\n// after\nlet (...) = match plan {\n    Plan::Query { .. } => (...),\n    v => return Err(ErrorCode::Internal(format!(\"Input plan must be Query, but it's {}\", v))),\n};","handlingStrategy":"validation","validationCode":"-- ensure COPY INTO <table> source is an explicit SELECT\n-- good: COPY INTO t FROM (SELECT $1, $2 FROM @stage)\n-- avoid relying on implicit table/stage source binding","typeGuard":"if !matches!(plan, Plan::Query { .. }) {\n    return Err(ErrorCode::BadArguments(\"COPY INTO table source must be a SELECT\".into()));\n}","tryCatchPattern":"match plan {\n    Plan::Query { s_expr, metadata, bind_context, formatted_ast, .. } => build_query(...),\n    other => return Err(ErrorCode::Internal(format!(\"Input plan must be Query, but it's {}\", other))),\n}","preventionTips":["Use explicit SELECT sources for COPY INTO table statements","Verify COPY syntax against the docs for your Databend version after upgrades","Run EXPLAIN on the source SELECT to confirm it binds as a query before COPY"],"tags":["rust","unreachable-panic","copy-into-table","planner"],"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"}