{"record":{"id":"0376ec0016c83e29","repo":"iced-rs/iced","slug":"node-configuration-and-split-count-do-not-match","errorCode":null,"errorMessage":"Node configuration and split count do not match","messagePattern":"Node configuration and split count do not match","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"widget/src/pane_grid/node.rs","lineNumber":340,"sourceCode":"                    Axis::Vertical => (count_a.vertical(), count_b.vertical()),\n                };\n\n                let (region_a, region_b, ratio) = axis.split(\n                    current,\n                    *ratio,\n                    spacing,\n                    min_size * (a_factor + 1) as f32 + spacing * a_factor as f32,\n                    min_size * (b_factor + 1) as f32 + spacing * b_factor as f32,\n                );\n\n                let _ = splits.insert(*id, (*axis, *current, ratio));\n\n                a.compute_splits(spacing, min_size, &region_a, count_a, splits);\n                b.compute_splits(spacing, min_size, &region_b, count_b, splits);\n            }\n            (Node::Pane(_), Count::Pane) => {}\n            _ => {\n                unreachable!(\"Node configuration and split count do not match\")\n            }\n        }\n    }\n}\n\nimpl std::hash::Hash for Node {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        match self {\n            Node::Split {\n                id,\n                axis,\n                ratio,\n                a,\n                b,\n            } => {\n                id.hash(state);\n                axis.hash(state);\n                ((ratio * 100_000.0) as u32).hash(state);","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/iced-rs/iced/blob/d146509d893945de5c304cfaf4301335eee278bd/widget/src/pane_grid/node.rs#L322-L358","documentation":"`Node::compute_splits` pairs the pane_grid `Node` tree with a `Count` tree while walking, and hits an incompatible node/count combination (e.g. `Node::Pane` with `Count::Split`). The two structures were built from different tree versions, so the library declares the case unreachable and panics.","triggerScenarios":"Calling `split_regions`/layout code where the split-count tree does not mirror the current node tree: a split was added or removed after counts were computed, or a reconstructed node tree disagrees with persisted counts.","commonSituations":"Restoring a saved pane layout where the node tree was edited (splits added/removed) without regenerating counts; concurrent mutation of pane state; mismatched snapshots in custom layout tooling.","solutions":["Recompute the count tree from the exact same node tree right before computing splits.","Persist and restore node + count trees as a single unit; validate the loaded structure by re-walking nodes.","Ensure each split/close mutation regenerates counts before the next layout pass.","If it occurs in stock usage, report as an internal desync bug with a reproduction."],"exampleFix":"// before\nsplits_from_cache = cached_splits(state_at_load_time);\nnode.compute_splits(..., splits_from_cache, ...);\n// after\nsplits = state.split_counts(); // recomputed from the same Node tree\nnode.compute_splits(..., splits, ...);","handlingStrategy":"validation","validationCode":"fn splits_match(node: &Node, count: &Count) -> bool {\n    match (node, count) {\n        (Node::Split { a, b }, Count::Split { a: ca, b: cb }) => {\n            splits_match(a, ca) && splits_match(b, cb)\n        }\n        (Node::Pane(_), Count::Pane) => true,\n        _ => false,\n    }\n}","typeGuard":"fn is_valid_pair(node: &Node, count: &Count) -> bool {\n    !matches!(\n        (node, count),\n        (Node::Split { .. }, Count::Pane) | (Node::Pane(_), Count::Split { .. })\n    )\n}","tryCatchPattern":"// Guard before calling split_regions\nassert!(splits_match(&node, &count), \"regenerate split counts from the node tree\");\nnode.compute_splits(...);","preventionTips":["Recompute split counts immediately before each layout pass.","Persist node and count trees together; regenerate counts when deserialization is suspected stale.","Apply split/close mutations and count updates in the same message-processing step."],"tags":["rust","pane-grid","layout","invariant","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"d146509d893945de5c304cfaf4301335eee278bd","analyzedAt":"2026-09-11T16:54:14.229Z","contentChangedAt":"2026-09-11T16:54:14.229Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}