{"record":{"id":"d7d2f6fb6d119d25","repo":"iced-rs/iced","slug":"downcast-on-stateless-state","errorCode":null,"errorMessage":"Downcast on stateless state","messagePattern":"Downcast on stateless state","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/src/widget/tree.rs","lineNumber":255,"sourceCode":"impl State {\n    /// 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}","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/iced-rs/iced/blob/d146509d893945de5c304cfaf4301335eee278bd/core/src/widget/tree.rs#L237-L273","documentation":"`State::downcast_ref<T>` panics when the widget's `State` is `State::None`, i.e. the widget holds no state at all. The library treats downcasting a stateless state as a programming error rather than a recoverable condition, because the caller has already assumed a concrete state type exists. In iced, `State::None` is used for widgets with no state or as a placeholder after state removal.","triggerScenarios":"Calling `tree.get_state(widget_id).downcast_ref::<MyState>()` on a widget whose state was never created, was reset to `State::None` (e.g. via `tree.set_state(State::None)` or widget diffing/removal), or whose id points at a stale/removed widget entry.","commonSituations":"Accessing widget state before the first `view` pass populated it; ids invalidated after widget tree rebuilds; custom widgets that lazily create state but are queried earlier; reusing a widget id across two tree positions.","solutions":["Check the state kind before downcasting: match on the returned `State` and only call `downcast_ref` for `State::Some`.","Ensure state is initialized (e.g. via `State::new(...)` in the widget's `update`/`Widget::state`) before any downcast.","Verify the widget id is valid and the widget still exists in the tree at the time of access.","If a downcast can legitimately fail, use the internal `state.downcast_ref()` on the `State::Some` payload (returns `Option`/`Result`) instead of panicking."],"exampleFix":"// before\nlet s = tree.get_state(id).downcast_ref::<MyState>();\n// after\nlet s = match tree.get_state(id) {\n    widget::tree::State::Some(_) => tree.get_state(id).downcast_ref::<MyState>(),\n    widget::tree::State::None => return, // state not initialized yet\n};","handlingStrategy":"type-guard","validationCode":"let state = tree.get_state(id);\nlet is_ready = matches!(state, widget::tree::State::Some(_));\nif !is_ready { return; }","typeGuard":"fn has_state(state: &widget::tree::State) -> bool {\n    matches!(state, widget::tree::State::Some(_))\n}","tryCatchPattern":"// Rust panics are not catchable by Result; use std::panic::catch_unwind only at boundaries\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    tree.get_state(id).downcast_ref::<MyState>()\n}));","preventionTips":["Always initialize widget state before first downcast (check `is_some` in `update`).","Never cache widget ids across tree rebuilds without validating them.","Prefer matching on `State` over blind downcasting in custom widgets.","Add debug assertions on id validity in widget code."],"tags":["rust","downcast","panic","state","widgets"],"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-14T00:17:10.932Z"}