{"record":{"id":"926f0f2dece81260","repo":"iced-rs/iced","slug":"downcast-widget-state","errorCode":null,"errorMessage":"Downcast widget state","messagePattern":"Downcast widget state","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/src/widget/tree.rs","lineNumber":235,"sourceCode":"    /// Creates a new [`State`].\n    pub fn new<T>(state: T) -> Self\n    where\n        T: 'static,\n    {\n        State::Some(Box::new(state))\n    }\n\n    /// Downcasts the [`State`] to `T` and returns a reference to it.\n    ///\n    /// # Panics\n    /// This method will panic if the downcast fails or the [`State`] is [`State::None`].\n    pub fn downcast_ref<T>(&self) -> &T\n    where\n        T: 'static,\n    {\n        match self {\n            State::None => panic!(\"Downcast on stateless state\"),\n            State::Some(state) => state.downcast_ref().expect(\"Downcast widget state\"),\n        }\n    }\n\n    /// Downcasts the [`State`] to `T` and returns a mutable reference to it.\n    ///\n    /// # Panics\n    /// This method will panic if the downcast fails or the [`State`] is [`State::None`].\n    pub fn downcast_mut<T>(&mut self) -> &mut T\n    where\n        T: 'static,\n    {\n        match self {\n            State::None => panic!(\"Downcast on stateless state\"),\n            State::Some(state) => state.downcast_mut().expect(\"Downcast widget state\"),\n        }\n    }\n}\n","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/iced-rs/iced/blob/2cffa99b395d84fe469b44dccb56bbacd2f1a157/core/src/widget/tree.rs#L217-L253","documentation":"`widget::Tree` stores each widget's state as a type-erased `Box<dyn Any>`; `State::downcast_ref::<T>()` panics with \"Downcast widget state\" when the stored concrete type is not `T` (a separate message, \"Downcast on stateless state\", covers `State::None`). It is an invariant check that the widget asking for state is the widget that created it.","triggerScenarios":"Calling `tree.state.downcast_ref::<T>()` where the Tree node was built by a widget whose `state()` returned a different type — custom widgets whose view/operate/diff code assumes another widget's state, or a reused tree whose nodes line up with different widgets after a structural change.","commonSituations":"Implementing a custom Widget/Operate with the wrong state type parameter; changing a widget's state struct between versions while tree diffing reuses nodes; reordering unkeyed list children so state nodes misalign; copy-pasting a custom widget without updating its state type.","solutions":["Make `T` exactly the type the widget returns from `Widget::state()`","Guard before downcasting: check the state is `State::Some` and `(*any).is::<T>()` before calling downcast_ref","Give list items stable keys so reordering cannot misalign state nodes","Return a dedicated state type from your widget and never downcast state you did not create"],"exampleFix":"// before\nlet state = tree.state.downcast_ref::<MyState>(); // panics on mismatch\n// after\nuse iced_core::widget::tree::State;\nmatch &tree.state {\n    State::Some(any) if (*any).is::<MyState>() => {\n        let state = tree.state.downcast_ref::<MyState>();\n        // ...\n    }\n    _ => { /* not our state: skip or log */ }\n}","handlingStrategy":"type-guard","validationCode":"use iced_core::widget::tree::State;\n\nfn can_downcast<T: 'static>(tree: &iced_core::widget::Tree) -> bool {\n    match &tree.state {\n        State::None => false,\n        State::Some(any) => any.is::<T>(),\n    }\n}\n\n// usage\nif can_downcast::<MyState>(tree) {\n    let state = tree.state.downcast_ref::<MyState>();\n}","typeGuard":"fn tree_state_is<T: 'static>(tree: &iced_core::widget::Tree) -> bool {\n    matches!(&tree.state, iced_core::widget::tree::State::Some(any) if any.is::<T>())\n}","tryCatchPattern":null,"preventionTips":["Only downcast state your own widget created via Widget::state()","Give dynamic children stable keys so tree nodes cannot misalign after reordering","When changing a widget's state type, treat it as a breaking change for tree reuse","Log the expected vs actual TypeId in your guard to make mismatches debuggable"],"tags":["rust","iced","widget","state","downcast","any","panic"],"backgroundTag":"any-downcast-failed","analyzedSha":"2cffa99b395d84fe469b44dccb56bbacd2f1a157","analyzedAt":"2026-08-16T19:41:49.083Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}