{"record":{"id":"9bc29db229186edc","repo":"iced-rs/iced","slug":"read-last-palette","errorCode":null,"errorMessage":"Read last palette","messagePattern":"Read last palette","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"debug/src/lib.rs","lineNumber":172,"sourceCode":"        };\n    }\n\n    pub fn quit() -> bool {\n        if BEACON.is_connected() {\n            BEACON.quit();\n\n            true\n        } else {\n            false\n        }\n    }\n\n    pub fn theme_changed(f: impl FnOnce() -> Option<palette::Seed>) {\n        let Some(palette) = f() else {\n            return;\n        };\n\n        if METADATA.read().expect(\"Read last palette\").theme.as_ref() != Some(&palette) {\n            log(client::Event::ThemeChanged(palette));\n\n            METADATA.write().expect(\"Write last palette\").theme = Some(palette);\n        }\n    }\n\n    pub fn tasks_spawned(amount: usize) {\n        log(client::Event::CommandsSpawned(amount));\n    }\n\n    pub fn subscriptions_tracked(amount: usize) {\n        log(client::Event::SubscriptionsTracked(amount));\n    }\n\n    pub fn layers_rendered(amount: impl FnOnce() -> usize) {\n        log(client::Event::LayersRendered(amount()));\n    }\n","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/iced-rs/iced/blob/2cffa99b395d84fe469b44dccb56bbacd2f1a157/debug/src/lib.rs#L154-L190","documentation":"`debug::theme_changed` compares a freshly applied palette seed against the last one reported to the beacon; the `.read().expect(\"Read last palette\")` fails when the global METADATA RwLock is poisoned by a prior panic under one of its guards. The closure `f` runs before locking, so the poison must originate elsewhere.","triggerScenarios":"Every theme/palette change in an app built with iced's debug feature, once the METADATA lock has been poisoned by an earlier panic (e.g. inside BEACON initialization or a previous theme_changed write).","commonSituations":"Live theme switching during a debug session after any swallowed panic; multithreaded apps where a panic on a worker thread poisoned METADATA before the UI thread changed themes.","solutions":["Locate the first panic that poisoned METADATA — this read is a cascade","Recover from poison in the library: `read().unwrap_or_else(PoisonError::into_inner)`","Keep panics out of code paths that hold METADATA guards (they are all inside debug/src/lib.rs)","Ship without the debug feature in production"],"exampleFix":"// before\nif METADATA.read().expect(\"Read last palette\").theme.as_ref() != Some(&palette) {\n// after\nif METADATA\n    .read()\n    .unwrap_or_else(std::sync::PoisonError::into_inner)\n    .theme\n    .as_ref() != Some(&palette)\n{","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let _ = std::panic::catch_unwind(|| debug::theme_changed(|| current_palette()));","preventionTips":["Fix the root-cause panic that poisoned METADATA — theme logging is a victim, not the cause","Avoid continuing to run after a swallowed panic in debug-instrumented builds","Keep theme_changed callbacks cheap and panic-free; they run on every theme swap","Run stress scenarios with the debug feature off to isolate rendering bugs from telemetry bugs"],"tags":["rust","iced","debug","theme","rwlock","lock-poisoning","panic"],"backgroundTag":"lock-poisoned","analyzedSha":"2cffa99b395d84fe469b44dccb56bbacd2f1a157","analyzedAt":"2026-08-16T19:41:49.083Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}