databendlabs/databend · error
Input plan must be Query, but it's
Error message
Input plan must be Query, but it's {} What it means
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.
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
Example fix
-- before (triggers panic on some builds) COPY INTO @stage FROM my_table FILE_FORMAT = (TYPE = CSV); -- after COPY INTO @stage FROM (SELECT * FROM my_table) FILE_FORMAT = (TYPE = CSV);
Defensive patterns
Strategy: validation
Validate before calling
-- ensure COPY INTO <location> source is an explicit SELECT -- good: COPY INTO @stage FROM (SELECT ...) -- avoid: COPY INTO @stage FROM <table> on builds that bind it non-query
Type guard
if !matches!(plan, Plan::Query { .. }) {
return Err(ErrorCode::BadArguments("COPY INTO location source must be a SELECT".into()));
} Try / catch
match plan {
Plan::Query { s_expr, metadata, bind_context, formatted_ast, .. } => build(...),
other => Err(ErrorCode::Internal(format!("Input plan must be Query, but it's {}", other))),
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- logic error: expected CreateTable plan
- Input plan must be Query, but it's
- internal error: entered unreachable code
- table name is provided
- internal error: entered unreachable code
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/595431d9d84d18a2.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/service/src/interpreters/interpreter_copy_into_location.rs:64
/// Create a CopyInterpreter with context and [`CopyIntoLocationPlan`].
pub fn try_create(ctx: Arc<QueryContext>, plan: CopyIntoLocationPlan) -> Result<Self> {
Ok(CopyIntoLocationInterpreter { ctx, plan })
}
#[async_backtrace::framed]
async fn build_query(
&self,
query: &Plan,
) -> Result<(SelectInterpreter, Vec<UpdateStreamMetaReq>)> {
let (s_expr, metadata, bind_context, formatted_ast) = match query {
Plan::Query {
s_expr,
metadata,
bind_context,
formatted_ast,
..
} => (s_expr, metadata, bind_context, formatted_ast),
v => unreachable!("Input plan must be Query, but it's {}", v),
};
let select_interpreter = SelectInterpreter::try_create(
self.ctx.clone(),
*(bind_context.clone()),
*s_expr.clone(),
metadata.clone(),
formatted_ast.clone(),
false,
)?;
let update_stream_meta = dml_build_update_stream_req(self.ctx.clone()).await?;
Ok((select_interpreter, update_stream_meta))
}
/// Build a pipeline for local copy into stage.
#[async_backtrace::framed]View on GitHub (pinned to 288d84d76e)