influxdata/influxdb · error
No statistics for input plan
Error message
No statistics for input plan
What it means
The per-plan statistics aggregation visitor keeps a stack of input statistics that must mirror the plan tree traversal: every child plan pushed statistics during pre_visit. When post_visit pops the stack and it is empty, the traversal invariant is broken; expect() panics with 'No statistics for input plan'.
Solutions
- Ensure every custom plan node is handled in pre_visit so its input statistics get pushed.
- Check the statistics source covers all node types in your plan (no unimplemented branches).
- Update the iox_query statistics aggregation after DataFusion version upgrades that alter plan structures.
- In a fork, replace expect with returning an internal-error Result for cleaner failure.
Example fix
// before
let statistics = self.statistics.pop_back().expect("No statistics for input plan");
// after
let statistics = self.statistics.pop_back().ok_or_else(|| {
internal_err!("No statistics for input plan")
})?; Defensive patterns
Strategy: try-catch
Validate before calling
// before running aggregation, ensure every plan node type is handled: // walk the plan and confirm each node's children are known to the stats source assert_plan_nodes_supported(&plan);
Try / catch
// this is a panic from expect(); catch via catch_unwind at integration boundaries only
let result = std::panic::catch_unwind(|| compute_statistics(&plan));
match result {
Ok(stats) => stats,
Err(_) => /* fall back to default statistics */,
} Prevention
- Handle all custom plan nodes in the statistics pre_visit so inputs are always pushed.
- Keep statistics aggregation in sync after DataFusion upgrades.
- Prefer returning Result over expect for stack underflow in a fork.
- Add a debug assertion that stack depth matches plan children counts during traversal.
When it happens
Trigger: Running the statistics aggregation over a logical plan where a custom/modified plan node or an overridden pre_visit skipped pushing statistics for a child, so post_visit finds the stack empty.
Common situations: Integrating custom LogicalPlan nodes not recognized by the statistics source; patched DataFusion plan visitors; bugs in statistics collection after planner upgrades changing node child counts.
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
- If we can remove a value from the interned strings, we must…
- invalid statistics
- Key column, , of current batch has no data
- Key column, , of last_batch has no data
- min ( ) > max ( )
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/f37d74bd784bbee8.
Report an issue: GitHub.
Appendix: source
Thrown at core/iox_query/src/statistics/aggregate_per_plan.rs:190
.is_some()
{
true
} else if plan.as_any().downcast_ref::<ProjectionExec>().is_some() {
// ProjectionExec is a special case. Only union stats if it includes pure columns
projection_includes_pure_columns(
plan.as_any().downcast_ref::<ProjectionExec>().unwrap(),
)
} else {
false
};
// pop statistics of all inputs from the stack
let num_inputs = plan.children().len();
// num_input must > 0. Pop the first one
let mut statistics = self
.statistics
.pop_back()
.expect("No statistics for input plan");
// pop the rest and update the min and max
for _ in 1..num_inputs {
let input_statistics = self
.statistics
.pop_back()
.expect("No statistics for input plan");
if union_stats {
// Conservatively union min max
statistics.null_count = statistics.null_count.add(&input_statistics.null_count);
statistics.max_value = statistics.max_value.max(&input_statistics.max_value);
statistics.min_value = statistics.min_value.min(&input_statistics.min_value);
statistics.distinct_count = Precision::Absent;
};
}
if union_stats {
self.statistics.push_back(statistics);View on GitHub (pinned to 06200ef96b)