iced-rs/iced · error
Write application metadata
Error message
Write application metadata
What it means
With iced's debug instrumentation enabled, `debug::init` stores the application `Metadata` (name, theme, time-travel capability) in a global `RwLock`. The `.expect("Write application metadata")` panics when that lock is poisoned by an earlier panic that occurred while a METADATA guard was held; re-entrant init while the BEACON LazyLock holds the read lock would deadlock instead.
Source
Thrown at debug/src/lib.rs:150
use crate::core::time::Instant;
use crate::core::window;
use crate::futures::Subscription;
use crate::futures::futures::Stream;
use crate::{Command, Metadata, Primitive};
use iced_beacon as beacon;
use beacon::client::{self, Client};
use beacon::span;
use beacon::span::present;
use std::sync::atomic::{self, AtomicBool, AtomicUsize};
use std::sync::{LazyLock, RwLock};
pub fn init(metadata: Metadata) {
let name = metadata.name.split("::").next().unwrap_or(metadata.name);
*METADATA.write().expect("Write application metadata") = client::Metadata {
name,
theme: metadata.theme,
can_time_travel: metadata.can_time_travel,
};
}
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 {View on GitHub (pinned to 2cffa99b39)
Solutions
- Find the ORIGINAL panic that poisoned METADATA — this expect is secondary
- Call debug::init exactly once, at program start, before spawning tasks/threads that log events
- As a maintainer: `write().unwrap_or_else(PoisonError::into_inner)` keeps debug telemetry alive after poisoning
- Disable the debug feature in release builds to remove the surface entirely
Example fix
// before
*METADATA.write().expect("Write application metadata") = client::Metadata { .. };
// after
*METADATA.write().unwrap_or_else(std::sync::PoisonError::into_inner) = client::Metadata { .. }; Defensive patterns
Strategy: fallback
Try / catch
// don't let debug telemetry abort the app let _ = std::panic::catch_unwind(|| debug::init(metadata));
Prevention
- Call debug::init exactly once at program start, before spawning threads or tasks
- Remember this panic is a cascade: hunt the earlier panic that poisoned METADATA first
- Disable the debug feature in release/CI runs where telemetry is not the subject under test
- If you maintain a fork, use unwrap_or_else(PoisonError::into_inner) on METADATA guards
When it happens
Trigger: Calling `debug::init(metadata)` once the METADATA RwLock is already poisoned — e.g. a prior panic inside theme_changed or BEACON initialization on another thread left it poisoned. Also reachable if init is called lazily (on first log event) rather than at startup, racing other debug calls.
Common situations: Debug feature enabled under stress tests where an unrelated earlier panic poisoned the static; a crash-reporting wrapper that swallows the first panic so only this cascade is visible; calling init from multiple threads.
Related errors
AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16).
Data as JSON: /api/errors/8a4f436a2795de44.
Report an issue: GitHub.