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
- Simplify the query to only supported operators (scan, filter, projection) for the DataFusion/Iceberg path.
- Execute the query via the regular RisingWave batch engine instead of the DataFusion path.
- 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
- Restrict DataFusion-path queries to scan/filter/projection shapes
- Default complex queries (joins, aggregates, windows) to the native batch engine
- Update the translator whenever new batch plan nodes are introduced
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
- Generating plan error
- Missing Iceberg Scan
- bounded compaction is not supported for copy-on-write tasks
- Iceberg metadata relations are not supported in streaming…
- Snowflake catalog only supports iceberg sources
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)