iced-rs/iced · error

Hot function is stale

Error message

Hot function is stale

What it means

`hot::call` wraps your function in an FnOnce closure consumed exactly once via `f.take().expect("Hot function is stale")`. The panic means the subsecond/cargo-hot runtime invoked the wrapper closure a second time after the FnOnce was already taken — stale code for the function ran again after (or during) a hotpatch swap, violating the run-once invariant.

Source

Thrown at debug/src/lib.rs:445

            if HOT_FUNCTIONS.get().is_none() {
                HOT_FUNCTIONS
                    .set(std::mem::take(
                        &mut HOT_FUNCTIONS_PENDING.lock().expect("Lock hot functions"),
                    ))
                    .expect("Set hot functions");
            }

            IS_STALE.store(false, atomic::Ordering::Relaxed);
        }));
    }

    pub fn call<O>(f: impl FnOnce() -> O) -> O {
        let mut f = Some(f);

        // The `move` here is important. Hotpatching will not work
        // otherwise.
        let mut f = cargo_hot::subsecond::HotFn::current(move || {
            f.take().expect("Hot function is stale")()
        });

        let address = f.ptr_address().0;

        if let Some(hot_functions) = HOT_FUNCTIONS.get() {
            if hot_functions.contains(&address) {
                IS_STALE.store(true, atomic::Ordering::Relaxed);
            }
        } else {
            let _ = HOT_FUNCTIONS_PENDING
                .lock()
                .expect("Lock hot functions")
                .insert(address);
        }

        f.call(())
    }

View on GitHub (pinned to 2cffa99b39)

Solutions

  1. Make hot-instrumented entry points non-reentrant (hoist recursion out of functions wrapped by hot::call)
  2. Ensure only one subsecond handler/init path is registered (duplicate handlers re-dispatch stale frames)
  3. Align cargo-hot/subsecond versions with the iced debug crate and restart the hot-reload session
  4. If reproducible with hotpatching disabled, or deterministic on one input, report upstream to iced/cargo-hot with the backtrace
Defensive patterns

Strategy: validation

Try / catch

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| hot::call(work)));
if result.is_err() {
    // stale-frame invariant broken: end the hot-reload session, keep the process
    log::error!("hot function executed twice — restart the hot-reload session");
}

Prevention

When it happens

Trigger: Re-entrant execution of a hot-instrumented function while a patch is being applied; a hotpatched function reached from multiple dispatch paths where cargo-hot swaps it mid-flight; subsecond replaying a frame after a patch.

Common situations: Editing recursive or mutually recursive functions under iced hot reload; long-running frames where the patched function is on the stack when the patch lands; version mismatch between cargo-hot/subsecond and iced's debug crate.

Related errors


AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16). Data as JSON: /api/errors/10cac6d603115e42. Report an issue: GitHub.