iced-rs/iced · error
Write last palette
Error message
Write last palette
What it means
After deciding the palette actually changed, `debug::theme_changed` records it with `METADATA.write().expect("Write last palette")`. The expect fires only when the RwLock is poisoned — an earlier panic held a guard — since the write itself cannot fail otherwise.
Source
Thrown at debug/src/lib.rs:175
pub fn quit() -> bool {
if BEACON.is_connected() {
BEACON.quit();
true
} else {
false
}
}
pub fn theme_changed(f: impl FnOnce() -> Option<palette::Seed>) {
let Some(palette) = f() else {
return;
};
if METADATA.read().expect("Read last palette").theme.as_ref() != Some(&palette) {
log(client::Event::ThemeChanged(palette));
METADATA.write().expect("Write last palette").theme = Some(palette);
}
}
pub fn tasks_spawned(amount: usize) {
log(client::Event::CommandsSpawned(amount));
}
pub fn subscriptions_tracked(amount: usize) {
log(client::Event::SubscriptionsTracked(amount));
}
pub fn layers_rendered(amount: impl FnOnce() -> usize) {
log(client::Event::LayersRendered(amount()));
}
pub fn boot() -> Span {
span(span::Stage::Boot)
}View on GitHub (pinned to 2cffa99b39)
Solutions
- Fix the root-cause panic that poisoned METADATA first
- Recover instead of panicking: `write().unwrap_or_else(PoisonError::into_inner)`
- Initialize debug state once at startup so later writes are single-threaded until the runtime spreads
- Disable the debug feature where it is not needed
Example fix
// before
METADATA.write().expect("Write last palette").theme = Some(palette);
// after
METADATA
.write()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.theme = Some(palette); Defensive patterns
Strategy: fallback
Try / catch
let _ = std::panic::catch_unwind(|| debug::theme_changed(|| current_palette()));
Prevention
- Treat the METADATA write panic as evidence of an earlier poisoning panic elsewhere
- Do not swallow panics with catch_unwind and keep the app running — poisoning spreads to later lock users
- Gate theme telemetry behind the debug feature only in development builds
- Maintainers: unwrap_or_else(PoisonError::into_inner) makes palette tracking survive poisoning
When it happens
Trigger: A theme change in a debug-instrumented app after the METADATA lock was poisoned by an earlier panic under one of its guards (init, BEACON LazyLock, or a prior theme_changed call).
Common situations: Debug builds with live theme switching after a swallowed panic; multiple threads logging theme events while a crash reporter masks the original failure.
Related errors
- Read last palette
- Write application metadata
- Read application metadata
- Lock hot functions
- Write to font system
AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16).
Data as JSON: /api/errors/57272d307c48b2fa.
Report an issue: GitHub.