cube-js/cube · error

Unsupported extension node: {}

Error message

Unsupported extension node: {}

What it means

During LogicalPlan-to-Cube-plan conversion, LogicalPlan::Extension nodes (DataFusion's escape hatch for custom, user-defined plan nodes) have no mapping into Cube's plan language and trigger an explicit panic. The message includes the extension node's schema for diagnostics.

Source

Thrown at rust/cubesql/cubesql/src/compile/rewrite/converter.rs:821

                self.graph
                    .add(LogicalPlanLanguage::Limit([skip, fetch, input]))
            }
            LogicalPlan::Values(values) => {
                let values = add_data_node!(self, values.values, ValuesValues);
                self.graph.add(LogicalPlanLanguage::Values([values]))
            }
            LogicalPlan::CreateExternalTable { .. } => {
                panic!("CreateExternalTable is not supported");
            }
            LogicalPlan::Explain { .. } => {
                panic!("Explain is not supported");
            }
            LogicalPlan::Analyze { .. } => {
                panic!("Analyze is not supported");
            }
            // TODO
            LogicalPlan::Extension(ext) => {
                panic!("Unsupported extension node: {}", ext.node.schema());
            }
            LogicalPlan::Distinct(distinct) => {
                let input = self.add_logical_plan_replace_params(
                    distinct.input.as_ref(),
                    query_params,
                    ctx,
                )?;
                self.graph.add(LogicalPlanLanguage::Distinct([input]))
            }
            // TODO: Support all
            _ => unimplemented!("Unsupported node type: {:?}", plan),
        })
    }
    fn find_source_table_name(&self, plan: &LogicalPlan) -> Result<Option<String>, CubeError> {
        Ok(match plan {
            LogicalPlan::Projection(node) => self.find_source_table_name(node.input.as_ref())?,
            LogicalPlan::Filter(node) => self.find_source_table_name(node.input.as_ref())?,
            LogicalPlan::Window(node) => self.find_source_table_name(node.input.as_ref())?,

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Identify the extension node name from the schema in the message and rewrite the query without it
  2. Upgrade CubeSQL — many extension nodes are later given real conversions
  3. Open/consult a Cube issue for the specific operator to add a LogicalPlanLanguage mapping
Defensive patterns

Strategy: try-catch

Try / catch

// catch_unwind around planner entry, since this is a panic not a Result
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| planner.plan(sql)));
match result {
    Ok(plan) => plan,
    Err(p) => { log::error!("plan conversion failed: {:?}", p); Err(planning_failed_response()) }
}

Prevention

When it happens

Trigger: The plan being converted contains a custom/extension operator — e.g. a UDF node, a custom table function, or a DataFusion plugin node injected upstream of the converter.

Common situations: Using DataFusion extension points or third-party extensions with CubeSQL; a CubeSQL version where a newly added builtin operator is still represented as an Extension node; raw SQL that maps to an unsupported function.

Related errors


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