cube-js/cube · error

This query doesnt have a plan, because it already has values

Error message

This query doesnt have a plan, because it already has values for response

What it means

CubeSQL's as_physical_plan() panics when the QueryPlan is a terminal/meta variant (MetaOk, MetaTabular, CopyFrom, CreateEmptyTempTable). These plans carry their response values directly and never produce a physical execution plan.

Source

Thrown at rust/cubesql/cubesql/src/compile/plan.rs:141

    pub fn as_logical_plan(&self) -> LogicalPlan {
        self.try_as_logical_plan().cloned().unwrap()
    }

    pub async fn as_physical_plan(&self) -> Result<Arc<dyn ExecutionPlan>, CubeError> {
        match self {
            QueryPlan::DataFusionSelect(plan, ctx)
            | QueryPlan::CreateTempTable(plan, ctx, _, _, _) => {
                DataFrame::new(ctx.state.clone(), plan)
                    .create_physical_plan()
                    .await
                    .map_err(|e| CubeError::from(e))
            }
            QueryPlan::MetaOk(_, _)
            | QueryPlan::MetaTabular(_, _)
            | QueryPlan::CopyFrom(_)
            | QueryPlan::CreateEmptyTempTable(_) => {
                panic!("This query doesnt have a plan, because it already has values for response")
            }
        }
    }

    pub fn print(&self, pretty: bool) -> Result<String, CubeError> {
        match self {
            QueryPlan::DataFusionSelect(plan, _) | QueryPlan::CreateTempTable(plan, _, _, _, _) => {
                if pretty {
                    Ok(plan.display_indent().to_string())
                } else {
                    Ok(plan.display().to_string())
                }
            }
            QueryPlan::MetaOk(_, _)
            | QueryPlan::MetaTabular(_, _)
            | QueryPlan::CopyFrom(_)
            | QueryPlan::CreateEmptyTempTable(_) => Ok(
                "This query doesnt have a plan, because it already has values for response"

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Check the QueryPlan variant before calling as_physical_plan and handle MetaOk/MetaTabular/CopyFrom/CreateEmptyTempTable by extracting their values directly.
  2. Route meta queries through the response-returning path instead of physical planning.
  3. File/inspect upstream: this panic usually indicates a planner routing bug in cubesql.

Example fix

// before
let physical = plan.as_physical_plan()?;
// after
let physical = match plan {
    QueryPlan::MetaOk(..) | QueryPlan::MetaTabular(..) => return Ok(plan_response(plan)),
    _ => plan.as_physical_plan()?,
};
Defensive patterns

Strategy: type-guard

Type guard

fn is_plan_executable(plan: &QueryPlan) -> bool {
    !matches!(plan,
        QueryPlan::MetaOk(_, _)
        | QueryPlan::MetaTabular(_, _)
        | QueryPlan::CopyFrom(_)
        | QueryPlan::CreateEmptyTempTable(_))
}

Try / catch

// panic!, not Result — cannot catch in Rust; guard before calling
if is_plan_executable(&plan) {
    let physical = plan.as_physical_plan()?;
} else {
    return handle_meta_response(plan);
}

Prevention

When it happens

Trigger: Calling as_physical_plan() on a QueryPlan that already holds final response values (meta queries, COPY FROM, create-empty-temp-table) instead of a real query plan.

Common situations: Planner bugs where a meta-response plan reaches the physical planning stage; custom SQL proxy code misinterpreting plan variants; queries like COPY FROM routed through the normal plan path.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/134a341f763f99d4. Report an issue: GitHub.