risingwavelabs/risingwave · error
unreachable
Error message
unreachable
What it means
LogicalIcebergScan is an internal optimizer node whose column pruning is expected to have already been performed by LogicalIcebergIntermediateScan. When prune_col is nevertheless invoked on it, the code declares the situation unreachable and panics with 'unreachable'. This is an internal invariant: seeing it indicates an optimizer rule ordering bug, not user error.
Source
Thrown at src/frontend/src/optimizer/plan_node/logical_iceberg_scan.rs:100
vec![
("source", src),
("columns", column_names_pretty(self.schema())),
(
"iceberg_scan_type",
Pretty::debug(&self.iceberg_scan_type()),
),
]
} else {
vec![]
};
childless_record("LogicalIcebergScan", fields)
}
}
impl ColPrunable for LogicalIcebergScan {
fn prune_col(&self, _: &[usize], _: &mut ColumnPruningContext) -> PlanRef {
// Column pruning should have been done in LogicalIcebergIntermediateScan.
unreachable!()
}
}
impl ExprRewritable<Logical> for LogicalIcebergScan {}
impl ExprVisitable for LogicalIcebergScan {}
impl PredicatePushdown for LogicalIcebergScan {
fn predicate_pushdown(
&self,
predicate: Condition,
_ctx: &mut PredicatePushdownContext,
) -> PlanRef {
// Predicate pushdown should have been done in LogicalIcebergIntermediateScan.
LogicalFilter::create(self.clone().into(), predicate)
}
}
View on GitHub (pinned to 6469eb736d)
Solutions
- Reproduce the SQL and file a bug / check recent changes: LogicalIcebergScan should be replaced by LogicalIcebergIntermediateScan before column pruning.
- Upgrade RisingWave to a version where the Iceberg planning pipeline handles pruning correctly.
- If developing, change the rule pipeline so Iceberg scans are converted before ColPrunable runs, or implement prune_col properly (delegate to LogicalIcebergIntermediateScan) instead of unreachable!().
Example fix
// before
fn prune_col(&self, _: &[usize], _: &mut ColumnPruningContext) -> PlanRef {
unreachable!()
}
// after
fn prune_col(&self, required_cols: &[usize], ctx: &mut ColumnPruningContext) -> PlanRef {
LogicalIcebergIntermediateScan::new(self.core.clone(), self.ctx()).prune_col(required_cols, ctx)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Not applicable to users: this is an internal optimizer invariant panic. // For developers: assert the rewrite happened before pruning. debug_assert!(matches!(plan, PlanRef::LogicalIcebergIntermediateScan(_) | _), "Iceberg scan must be converted before pruning");
Type guard
fn is_iceberg_intermediate_scan(node: &PlanRef) -> bool {
matches!(node.as_logical(), Some(LogicalNode::IcebergIntermediateScan(_)))
} Try / catch
// In Rust, catch_unwind around planner invocations in services that must not crash
let result = std::panic::catch_unwind(|| planner.prune_cols(plan));
match result {
Ok(r) => r?,
Err(_) => return Err(anyhow!("optimizer panicked on Iceberg scan; report this bug")),
} Prevention
- Report this panic upstream with the SQL — it indicates an optimizer bug, not user error.
- Avoid local patches that add pruning rules matching LogicalIcebergScan.
- Ensure Iceberg-to-IntermediateScan rewrite ordering in the rule pipeline.
- Pin to a RisingWave release where Iceberg column pruning is handled by LogicalIcebergIntermediateScan.
When it happens
Trigger: The column pruning pass calls prune_col on a LogicalIcebergScan node — possible when an Iceberg query's plan is not correctly rewritten into LogicalIcebergIntermediateScan before pruning, or when new optimizer rules route Iceberg scans through pruning.
Common situations: Optimizer bug after changes to Iceberg source planning; a query shape over an Iceberg source that skips the intermediate-scan rewrite; local patches to the frontend that add pruning rules matching Iceberg scans.
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
- IcebergSinkWriter should be initialized before barrier
- Iceberg metadata relations are not supported in streaming qu
- insert should always be converted to batch plan
- unimplemented
- not yet implemented
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/0bf5f4e153da8f94.
Report an issue: GitHub.