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

  1. Find the ORIGINAL panic that poisoned METADATA — this expect is secondary
  2. Call debug::init exactly once, at program start, before spawning tasks/threads that log events
  3. As a maintainer: `write().unwrap_or_else(PoisonError::into_inner)` keeps debug telemetry alive after poisoning
  4. 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

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.