databendlabs/databend · error
Input plan must be Query, but it's
Error message
Input plan must be Query, but it's {} What it means
connect_query_plan_source destructures the input plan expecting it to be the Query variant; only then can it extract the SExpr/metadata/bind_context needed to build a SelectInterpreter. Any other Plan variant (e.g. an already-physical or DML plan) violates the assumption and panics via unreachable! with the actual variant.
Solutions
- Check the optimizer output for the REPLACE source query and confirm it remains Plan::Query.
- Upgrade/patch the planner so REPLACE sources are kept as Query plans until interpretation.
- Work around by using a simpler source form (plain SELECT) that reliably produces a Query plan.
Example fix
// before
v => unreachable!("Input plan must be Query, but it's {}", v),
// after
v => Err(ErrorCode::Internal(format!(
"REPLACE source must be a Query plan, got: {}", v
))), Defensive patterns
Strategy: type-guard
Validate before calling
// Verify the source plan variant before destructuring
if !matches!(plan, Plan::Query { .. }) {
return Err(ErrorCode::Internal("REPLACE source is not a Query plan".into()));
} Type guard
fn is_query_plan(p: &Plan) -> bool {
matches!(p, Plan::Query { .. })
} Prevention
- Add planner tests asserting REPLACE sources stay Plan::Query
- Handle new Plan variants in every destructuring site
- Return structured Internal errors instead of unreachable!
When it happens
Trigger: Running REPLACE INTO ... <source> where the logical plan of the source is not Plan::Query — e.g. the planner handed back a different plan node for the SELECT part.
Common situations: Planner rewrites or optimizer changes that substitute a non-Query plan for the REPLACE source; embedding REPLACE with an EXPLAIN-derived or cached plan object.
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
- replace with streaming not supported yet
- 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
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/9c68b16a9bcde322.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/service/src/interpreters/interpreter_replace.rs:482
meta: PhysicalPlanMeta::new("ReplaceAsyncSourcer"),
}))
}
#[async_backtrace::framed]
async fn connect_query_plan_source<'a>(
&'a self,
ctx: Arc<QueryContext>,
query_plan: &Plan,
) -> Result<ReplaceSourceCtx> {
let (s_expr, metadata, bind_context, formatted_ast) = match query_plan {
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 update_stream_meta = dml_build_update_stream_req(self.ctx.clone()).await?;
let select_interpreter = SelectInterpreter::try_create(
ctx.clone(),
*(bind_context.clone()),
*s_expr.clone(),
metadata.clone(),
formatted_ast.clone(),
false,
)?;
let physical_plan = select_interpreter.build_physical_plan().await?;
let select_ctx = ReplaceSelectCtx {
select_column_bindings: bind_context.columns.clone(),
select_schema: query_plan.schema(),
};View on GitHub (pinned to 288d84d76e)