{"record":{"id":"4f650fa72ab5b8ff","repo":"slint-ui/slint","slug":"trying-to-upgrade-a-weak-from-a-different-thread-than-the","errorCode":null,"errorMessage":"Trying to upgrade a Weak from a different thread than the one it belongs to","messagePattern":"Trying to upgrade a Weak from a different thread than the one it belongs to","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/core/api.rs","lineNumber":1187,"sourceCode":"        /// This also returns None if the current thread is not the thread that created\n        /// the component\n        pub fn upgrade(&self) -> Option<T> {\n            #[cfg(feature = \"std\")]\n            if std::thread::current().id() != self.thread {\n                return None;\n            }\n            T::upgrade_from_weak_inner(&self.inner)\n        }\n\n        /// Convenience function that returns a new strongly referenced component if\n        /// some other instance still holds a strong reference and the current thread\n        /// is the thread that created this component.\n        /// Otherwise, this function panics.\n        #[track_caller]\n        pub fn unwrap(&self) -> T {\n            #[cfg(feature = \"std\")]\n            if std::thread::current().id() != self.thread {\n                panic!(\n                    \"Trying to upgrade a Weak from a different thread than the one it belongs to\"\n                );\n            }\n            T::upgrade_from_weak_inner(&self.inner)\n                .expect(\"The Weak doesn't hold a valid component\")\n        }\n\n        /// A helper function to allow creation on `component_factory::Component` from\n        /// a `ComponentHandle`\n        pub(crate) fn inner(&self) -> T::WeakInner {\n            self.inner.clone()\n        }\n\n        /// Convenience function that combines [`invoke_from_event_loop()`] with [`Self::upgrade()`]\n        ///\n        /// The given functor will be added to an internal queue and will wake the event loop.\n        /// On the next iteration of the event loop, the functor will be executed with a `T` as an argument.\n        ///","sourceCodeStart":1169,"sourceCodeEnd":1205,"githubUrl":"https://github.com/slint-ui/slint/blob/bb937076de3f7919766c1f25e2e969367cf77e9a/internal/core/api.rs#L1169-L1205","documentation":"Weak component handles in Slint are thread-affine: `Weak::unwrap()` records the thread of the creating component and panics if `unwrap()` is called from a different thread (with the std feature). This guards against upgrading a component handle from a non-UI thread, which is unsupported.","triggerScenarios":"Calling `weak.unwrap()` (or `upgrade()`) on a `Weak<T>`/`ComponentHandle` clone captured and moved into a non-UI thread, e.g. inside a `std::thread::spawn` closure or a background worker callback, when that thread differs from the one that created the component.","commonSituations":"Spawning a worker thread that tries to touch UI state; async runtimes (tokio) executing a closure on a thread pool; queueing a component handle for use in a backend thread.","solutions":["Perform UI access on the thread that created the component (the main/UI thread); use slint::invoke_from_event_loop or a `slint::VecModel` wrapped and updated via the event loop instead","Move raw data (not component handles) into the worker thread, then post results back with `slint::invoke_from_event_loop(move || { /* update UI */ })`","If spawning your own UI thread, create the component on that thread and only unwrap there"],"exampleFix":"// before\nlet weak = ui.as_weak();\nstd::thread::spawn(move || {\n    let ui = weak.unwrap(); // panics: wrong thread\n    ui.set_result(...);\n});\n// after\nlet weak = ui.as_weak();\nstd::thread::spawn(move || {\n    let result = compute();\n    slint::invoke_from_event_loop(move || {\n        weak.unwrap().set_result(result);\n    }).unwrap();\n});","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Rust\nfn same_thread(this_thread: std::thread::ThreadId) -> bool {\n    std::thread::current().id() == this_thread\n}","tryCatchPattern":"// prefer not to panic at all:\n// route UI access through the event loop\nslint::invoke_from_event_loop(move || {\n    if let Some(ui) = weak.upgrade() { ui.set_result(v); }\n}).unwrap();","preventionTips":["Never move ComponentHandle/Weak across threads; move plain data instead","Always update UI state via slint::invoke_from_event_loop from background threads","In async code, schedule UI mutations on the main/UI thread executor"],"tags":["rust","threading","weak-reference","ui-thread"],"backgroundTag":"thread-interrupted","analyzedSha":"bb937076de3f7919766c1f25e2e969367cf77e9a","analyzedAt":"2026-09-16T01:37:20.251Z","contentChangedAt":"2026-09-16T01:37:20.251Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}