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
- Immediately pass every SpawnToken to Spawner::spawn() and don't store or discard it
- Avoid early returns (?-operators, panics, matches) between token creation and spawn; bind the token right before spawning
- Do not wrap SpawnToken in Option/Result that might drop it; spawn unconditionally
- 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)