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

  1. Reproduce the SQL and file a bug / check recent changes: LogicalIcebergScan should be replaced by LogicalIcebergIntermediateScan before column pruning.
  2. Upgrade RisingWave to a version where the Iceberg planning pipeline handles pruning correctly.
  3. 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

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


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