iced-rs/iced · error
Node configuration and count do not match
Error message
Node configuration and count do not match
What it means
`Node::compute_regions` walks a pane_grid `Node` tree alongside a parallel `Count` tree and reaches a shape pair (node kind, count kind) that cannot correspond — e.g. a `Node::Split` paired with `Count::Pane`, or a `Node::Pane` paired with `Count::Split`. This indicates the count structure was computed from a different tree than the node tree, so the library calls `unreachable!`.
Source
Thrown at widget/src/pane_grid/node.rs:292
Axis::Vertical => (count_a.vertical(), count_b.vertical()),
};
let (region_a, region_b, _ratio) = axis.split(
current,
*ratio,
spacing,
min_size * (a_factor + 1) as f32 + spacing * a_factor as f32,
min_size * (b_factor + 1) as f32 + spacing * b_factor as f32,
);
a.compute_regions(spacing, min_size, ®ion_a, count_a, regions);
b.compute_regions(spacing, min_size, ®ion_b, count_b, regions);
}
(Node::Pane(pane), Count::Pane) => {
let _ = regions.insert(*pane, *current);
}
_ => {
unreachable!("Node configuration and count do not match")
}
}
}
fn compute_splits(
&self,
spacing: f32,
min_size: f32,
current: &Rectangle,
count: &Count,
splits: &mut BTreeMap<Split, (Axis, Rectangle, f32)>,
) {
match (self, count) {
(
Node::Split {
axis,
ratio,
a,View on GitHub (pinned to d146509d89)
Solutions
- Regenerate the `Count` tree from the same `PaneGridState`/node snapshot used for region computation so both structures match.
- If layout is persisted, save node and count together atomically and validate on load (recompute counts by walking the node tree).
- Check that split/close operations update the cached count structure in the same update cycle as the node mutation.
- Report if triggered by ordinary `PaneGrid` usage — it indicates an internal desync bug.
Example fix
// before counts = old_snapshot.counts(); // stale regions = node.compute_regions(..., counts, ...); // after counts = state.counts(); // derived from the same PaneGridState as `node` regions = node.compute_regions(..., counts, ...);
Defensive patterns
Strategy: validation
Validate before calling
// Re-derive counts from the same node snapshot before layout
fn counts_match(node: &Node, count: &Count) -> bool {
match (node, count) {
(Node::Split { a, b }, Count::Split { a: ca, b: cb }) => {
counts_match(a, ca) && counts_match(b, cb)
}
(Node::Pane(_), Count::Pane) => true,
_ => false,
}
} Type guard
fn is_consistent(node: &Node, count: &Count) -> bool {
matches!(
(node, count),
(Node::Split { .. }, Count::Split { .. }) | (Node::Pane(_), Count::Pane)
)
} Try / catch
// unreachable! panics; validate before calling pane_regions
if !is_consistent(&node, &count) { return Err("node/count desync"); }
let regions = node.compute_regions(...); Prevention
- Always derive Count trees from the exact same PaneGridState as the Node tree.
- Update nodes and counts atomically on split/close operations.
- Validate persisted layouts on load by walking the node tree.
- Avoid sharing node snapshots across update cycles.
When it happens
Trigger: Calling `pane_regions`/`PaneGrid::layout` where the `Count` snapshot and the `Node` tree were produced at different times — e.g. a pane was split/removed after the count was derived, or application code deserialized/constructed a mismatched node/count pair.
Common situations: Custom pane_grid state restoration (saving/loading layouts) where counts and nodes drift out of sync; racing state updates that split a pane while regions are computed; hand-built `Node` values in tests or custom widgets.
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
- Node configuration and split count do not match
- Caches must not be empty
- Downcast widget state
- Downcast on stateless state
- {error:?}
AI-assisted analysis of iced-rs/iced@d146509d89 (2026-09-11).
Data as JSON: /api/errors/dcf6c578e7a813e9.
Report an issue: GitHub.