databendlabs/databend · error
Input plan must be Query, but it's
Error message
Input plan must be Query, but it's {} What it means
The SET interpreter builds a sub-SELECT for assignment sources and destructures the input plan expecting the Query variant so it can construct a SelectInterpreter. If the plan is any other variant, the invariant is broken and the code panics via unreachable!, reporting the actual variant in the message.
Solutions
- Inspect the logical plan of the SET statement's right-hand side to see which non-Query variant is produced.
- Fix the planner so assignment sources are wrapped in Plan::Query, or add an arm handling the new variant.
- Upgrade to a version where SET source plans are guaranteed to be Query.
Example fix
// before
v => unreachable!("Input plan must be Query, but it's {}", v),
// after
v => Err(ErrorCode::Internal(format!(
"SET source must be a Query plan, got: {}", v
))), Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the SET source plan variant before destructuring
if !matches!(plan, Plan::Query { .. }) {
return Err(ErrorCode::Internal("SET source is not a Query plan".into()));
} Type guard
fn is_query_plan(p: &Plan) -> bool {
matches!(p, Plan::Query { .. })
} Prevention
- Add planner tests for SET assignment sources
- Update all Plan destructuring sites when adding variants
- Avoid unreachable! in user-reachable code paths
When it happens
Trigger: Executing a SET/assignment statement whose value-producing sub-plan is not Plan::Query — e.g. an optimizer/planner change yields a different logical plan node for the assigned expression source.
Common situations: Internal planner regressions when new plan nodes are introduced; using SET ... = (SELECT ...) forms through code paths that reshape the sub-plan.
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
- Input plan must be Query, but it's
- internal error: entered unreachable code
- create_procedure: CreateOrReplace should never conflict…
- plan in InsertInputSource::Stag must be CopyIntoTable
- replace with streaming not supported yet
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/1c76cb0f5697376d.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/service/src/interpreters/interpreter_set.rs:196
fn is_ddl(&self) -> bool {
false
}
#[async_backtrace::framed]
async fn execute2(&self) -> Result<PipelineBuildResult> {
let scalars = match &self.set.values {
SetScalarsOrQuery::VarValue(scalars) => scalars.clone(),
SetScalarsOrQuery::Query(query) => {
let (s_expr, metadata, bind_context, formatted_ast) = match query.as_ref() {
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 stream = select_interpreter
.execute_with_hooks(self.ctx.clone(), QueryFinishHooks::nested_with_hooks())
.await?;
let datablocks: Vec<DataBlock> = stream.try_collect::<Vec<_>>().await?;
let num_columns = bind_context.columns.len();
if num_columns != self.set.idents.len() {
return Err(ErrorCode::BadArguments(format!(View on GitHub (pinned to 288d84d76e)