{"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":256,"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":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/iced-rs/iced/blob/f8127c84dddf0b9e32c5e7dbb822911652f72665/core/src/widget/tree.rs#L238-L274","documentation":"The state exists (State::Some(Box<dyn Any>)) but Any::downcast_ref::<T>() returned None: the concrete type inside the box is not T. The expect(\"Downcast widget state\") fires, meaning a plain type mismatch between the state a widget stored via State::new and the type its consumer requested via downcast_ref.","triggerScenarios":"Calling downcast_ref::<T>() with a T different from the type the widget passed to State::new; a custom widget whose state type changed between builds while an old Tree is reused; downcasting the state row of a different widget (wrong child index) that stores another type; downcasting built-in widget internals whose state types are private and version-specific.","commonSituations":"Refactoring a custom widget's state struct without regenerating the tree; copy-pasted downcast_ref calls from another widget; relying on internal state types of TextInput/Scrollable-style widgets that changed across iced releases.","solutions":["Make T exactly the type the widget creates with State::new for that tree row","Re-check the tree traversal: the child index used for the downcast must be the child that owns the state","If you changed the state type of a custom widget, force state recreation (fresh Tree, or a widget change that makes diff rebuild the row)","Never rely on concrete internal state types of built-in iced widgets across versions; pin the iced version or use public APIs instead"],"exampleFix":"// before\nlet state = tree.state.downcast_ref::<OldState>(); // widget now stores NewState\n\n// after - match the type the widget creates\nimpl<Message, Renderer> Widget<Message, Renderer> for MyWidget {\n    fn state(&self) -> Option<tree::State> {\n        Some(tree::State::new(NewState::default()))\n    }\n}\nlet state = tree.state.downcast_ref::<NewState>();","handlingStrategy":"type-guard","validationCode":"// correlate the tree row with the state type before downcasting\nif tree.tag != tree::Tag::of::<MyState>() {\n    // wrong row or the widget stores a different type: fix traversal first\n}","typeGuard":"fn as_state<T: 'static>(state: &tree::State) -> Option<&T> {\n    match state {\n        tree::State::Some(inner) => inner.downcast_ref::<T>(),\n        tree::State::None => None,\n    }\n}","tryCatchPattern":null,"preventionTips":["Always pair State::new(T) and downcast_ref::<T> in the same module so they change together","Regenerate the widget tree after changing a custom widget's state type","Pin the iced version if you must depend on internal widget state types","Use tree.tag / Tag::of::<T>() to assert row ownership in debug builds"],"tags":["rust","iced","panic","downcast","type-mismatch","widget-tree"],"backgroundTag":"wrong-type-downcast","analyzedSha":"f8127c84dddf0b9e32c5e7dbb822911652f72665","analyzedAt":"2026-08-17T10:40:26.997Z","contentChangedAt":"2026-08-17T10:40:26.997Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}