risingwavelabs/risingwave · error · GenDataFusionPlanError

Unsupported Plan Node

Error message

Unsupported Plan Node

What it means

Variant of `GenDataFusionPlanError` thrown during DataFusion plan generation when the converter encounters a RisingWave logical plan node kind it does not know how to translate into a DataFusion `LogicalPlan`. Only a subset of batch plan nodes is supported for the Iceberg/DataFusion execution path.

Solutions

  1. Simplify the query to only supported operators (scan, filter, projection) for the DataFusion/Iceberg path.
  2. Execute the query via the regular RisingWave batch engine instead of the DataFusion path.
  3. Extend the plan translator's match to map the unsupported node to a DataFusion equivalent.

Example fix

// before
let df_plan = try_gen_datafusion_plan(&optimized_plan)?; // plan contains HashAgg
// after
// push aggregation out of the datafusion path, or handle it:
match node {
    PlanNode::IcebergScan(..) => translate_scan(node),
    other => return Err(GenDataFusionPlanError::UnsupportedPlanNode), // handled upstream
}
Defensive patterns

Strategy: fallback

Validate before calling

// check the query only uses supported operators before taking the DataFusion path
const unsupported = /JOIN|GROUP BY|OVER \(/i.test(sql);
if (unsupported) useRegularBatchEngine(sql);

Type guard

function planIsSupported(node) {
  return ["IcebergScan", "Project", "Filter"].includes(node.kind);
}

Try / catch

match try_gen_datafusion_plan(&plan) {
    Err(GenDataFusionPlanError::UnsupportedPlanNode) => {
      // fall back to RisingWave batch execution
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling `try_gen_datafusion_plan` on an optimized plan containing unsupported operators (e.g. joins, aggregations, or exchange nodes not mapped in the translator's match on plan node types).

Common situations: Running complex queries (joins, window functions, aggregations) against Iceberg tables via the DataFusion path where only simple scans/projections/filters are supported; new batch plan nodes added without updating the translator.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/8b759a190f8e8b5a. Report an issue: GitHub.

Appendix: source

Thrown at src/frontend/src/datafusion/execute/mod.rs:64

mod memory_ctx;
mod query_planner;

pub(crate) use memory_ctx::create_df_spillable_budget_ctx;
const DF_MANAGED_SPILL_DIR: &str = "df_batch_spill/";

#[derive(Clone)]
pub struct DfBatchQueryPlanResult {
    pub(crate) plan: Arc<LogicalPlan>,
    pub(crate) schema: RwSchema,
    pub(crate) stmt_type: StatementType,
}

#[derive(Debug, Error)]
pub enum GenDataFusionPlanError {
    #[error("Missing Iceberg Scan")]
    MissingIcebergScan,
    #[error("Unsupported Plan Node")]
    UnsupportedPlanNode,
    #[error("Generating plan error: {0}")]
    Generating(#[source] RwError),
}

pub fn try_gen_datafusion_plan(
    optimized_logical: &BatchOptimizedLogicalPlanRoot,
) -> Result<Arc<LogicalPlan>, GenDataFusionPlanError> {
    use crate::optimizer::DataFusionExecuteCheckerExt;

    let check_result = optimized_logical.plan.check_for_datafusion();
    if !check_result.have_iceberg_scan {
        return Err(GenDataFusionPlanError::MissingIcebergScan);
    }
    if !check_result.supported {
        return Err(GenDataFusionPlanError::UnsupportedPlanNode);
    }

View on GitHub (pinned to 6469eb736d)