embassy-rs/embassy · error

SpawnToken instances may not be dropped. You must pass them…

Error message

SpawnToken instances may not be dropped. You must pass them to Spawner::spawn()

What it means

Panic in SpawnToken's Drop impl: a SpawnToken carries ownership of a task's allocated state, and dropping it without spawning would leak that state permanently. The Drop impl therefore panics by design instead of silently leaking. It fires whenever a token returned by spawn-capable task methods (e.g. Spawner::spawn's argument-producing call sites, or make_spawn_token paths) is discarded — via unused result, early return between token creation and Spawner::spawn(), or wrapping the token in a scope that ends without spawning.

Solutions

  1. Immediately pass every SpawnToken to Spawner::spawn() and don't store or discard it
  2. Avoid early returns (?-operators, panics, matches) between token creation and spawn; bind the token right before spawning
  3. Do not wrap SpawnToken in Option/Result that might drop it; spawn unconditionally
  4. If conditional spawning is needed, only create the token after the condition is decided
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at embassy-executor/src/spawner.rs:54 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/edfc68b67fdc2c8a. Report an issue: GitHub.

Appendix: source

Thrown at embassy-executor/src/spawner.rs:54

    }

    /// Returns the task ID.
    /// This can be used in combination with trace to match task names with IDs
    pub fn id(&self) -> TaskId {
        self.raw_task.id()
    }

    /// Get the metadata for this task. You can use this to set metadata fields
    /// prior to spawning it.
    pub fn metadata(&self) -> MetadataRef {
        self.raw_task.metadata()
    }
}

impl<S> Drop for SpawnToken<S> {
    fn drop(&mut self) {
        // TODO deallocate the task instead.
        panic!("SpawnToken instances may not be dropped. You must pass them to Spawner::spawn()")
    }
}

/// Error returned when spawning a task.
#[derive(Copy, Clone)]
pub enum SpawnError {
    /// Too many instances of this task are already running.
    ///
    /// By default, a task marked with `#[embassy_executor::task]` can only have one instance
    /// running at a time. You may allow multiple instances to run in parallel with
    /// `#[embassy_executor::task(pool_size = 4)]`, at the cost of higher RAM usage.
    Busy,
}

impl core::fmt::Debug for SpawnError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        core::fmt::Display::fmt(self, f)
    }

View on GitHub (pinned to 463a07b963)