{"record":{"id":"595431d9d84d18a2","repo":"databendlabs/databend","slug":"input-plan-must-be-query-but-it-s","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_location.rs","lineNumber":64,"sourceCode":"    /// Create a CopyInterpreter with context and [`CopyIntoLocationPlan`].\n    pub fn try_create(ctx: Arc<QueryContext>, plan: CopyIntoLocationPlan) -> Result<Self> {\n        Ok(CopyIntoLocationInterpreter { 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 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        let update_stream_meta = dml_build_update_stream_req(self.ctx.clone()).await?;\n\n        Ok((select_interpreter, update_stream_meta))\n    }\n\n    /// Build a pipeline for local copy into stage.\n    #[async_backtrace::framed]","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/interpreters/interpreter_copy_into_location.rs#L46-L82","documentation":"build_query in interpreter_copy_into_location (src/query/service/src/interpreters/interpreter_copy_into_location.rs:64) destructures the bound plan expecting Plan::Query and panics with unreachable!(\"Input plan must be Query, but it's {}\") for any other variant. COPY INTO <location> requires its input to be a SELECT/query plan; a non-query plan reaching this interpreter is an internal invariant breach.","triggerScenarios":"Executing COPY INTO <stage/location> whose source binds to a non-Query plan — e.g. `COPY INTO @stage FROM (a non-select statement)` or a planner change that produces a different plan variant (Explain/DML wrappers) for the copy source.","commonSituations":"Users attempting COPY INTO a location from something other than a SELECT (a table name shortcut or unsupported source form) on a build where the binder no longer wraps it into a query plan; also seen after version upgrades that changed plan binding.","solutions":["Rewrite the COPY INTO statement so the source is an explicit SELECT, e.g. `COPY INTO @my_stage FROM (SELECT col1, col2 FROM my_table ...)`, since plain table sources may no longer bind as expected","Upgrade to a Databend version where the copy-into-location binder guarantees a Query plan or returns a proper user-facing error","If the statement already uses SELECT, file a bug with the exact SQL and version — the binder produced an unexpected plan variant","As a code fix, return ErrorCode::Internal with the variant name instead of panicking"],"exampleFix":"-- before (triggers panic on some builds)\nCOPY INTO @stage FROM my_table FILE_FORMAT = (TYPE = CSV);\n-- after\nCOPY INTO @stage FROM (SELECT * FROM my_table) FILE_FORMAT = (TYPE = CSV);","handlingStrategy":"validation","validationCode":"-- ensure COPY INTO <location> source is an explicit SELECT\n-- good: COPY INTO @stage FROM (SELECT ...)\n-- avoid: COPY INTO @stage FROM <table> on builds that bind it non-query","typeGuard":"if !matches!(plan, Plan::Query { .. }) {\n    return Err(ErrorCode::BadArguments(\"COPY INTO location source must be a SELECT\".into()));\n}","tryCatchPattern":"match plan {\n    Plan::Query { s_expr, metadata, bind_context, formatted_ast, .. } => build(...),\n    other => Err(ErrorCode::Internal(format!(\"Input plan must be Query, but it's {}\", other))),\n}","preventionTips":["Always wrap the COPY INTO location source in parentheses with SELECT","Test COPY statements after upgrading Databend","Keep stage copy syntax aligned with current docs rather than legacy forms"],"tags":["rust","unreachable-panic","copy-into-location","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"}