leptos-rs/leptos · critical
At {caller}, tried to spawn a Future with Executor::spawn()
Error message
At {caller}, tried to spawn a Future with Executor::spawn() before a global executor was initialized. What it means
In debug builds without the tracing feature, handle_uninitialized_spawn panics with this message when Executor::spawn is called before any global executor was initialized. The {caller} interpolation tells you which call site attempted the spawn. It is the diagnostic (as opposed to release no-op) path for the uninitialized-spawn condition.
Source
Thrown at any_spawner/src/lib.rs:474
/// Handles the case where `Executor::spawn` is called without an initialized executor.
#[cold] // Less likely path
#[inline(never)]
#[track_caller]
fn handle_uninitialized_spawn(_fut: PinnedFuture<()>) {
let caller = std::panic::Location::caller();
#[cfg(all(debug_assertions, feature = "tracing"))]
{
tracing::error!(
target: "any_spawner",
spawn_caller=%caller,
"Executor::spawn called before a global executor was initialized. Task dropped."
);
// Drop the future implicitly after logging
drop(_fut);
}
#[cfg(all(debug_assertions, not(feature = "tracing")))]
{
panic!(
"At {caller}, tried to spawn a Future with Executor::spawn() \
before a global executor was initialized."
);
}
// In release builds (without tracing), call the specific no-op function.
#[cfg(not(debug_assertions))]
{
no_op_spawn(_fut);
}
}
/// Handles the case where `Executor::spawn_local` is called without an initialized executor.
#[cold] // Less likely path
#[inline(never)]
#[track_caller]
fn handle_uninitialized_spawn_local(_fut: PinnedLocalFuture<()>) {
let caller = std::panic::Location::caller();
#[cfg(all(debug_assertions, feature = "tracing"))]View on GitHub (pinned to 32d20f6c9d)
Solutions
- Call any_spawner::spawn::set_executor(...) at the very start of the program/test before any spawn.
- In tests, add a shared initializer (e.g. once_cell Lazy) that sets a tokio or wasm executor.
- Check feature flags: enable tracing or the debug handler path you expect, or fix the init that a cfg gate disabled.
- Read the {caller} value in the panic message to find the offending spawn call and defer it until after executor init.
Example fix
// before
#[test]
fn spawns() {
Executor::spawn(async {}); // panics: no executor
}
// after
#[test]
fn spawns() {
any_spawner::spawn::set_executor(any_spawner::Executor::Tokio);
Executor::spawn(async {});
} Defensive patterns
Strategy: try-catch
Validate before calling
// The panic cannot be caught in-process via catch_unwind for normal use; validate init instead:
fn spawn_task<F: Future<Output = ()> + 'static>(fut: F) {
crate::init::ensure_global_executor(); // must run before any spawn
any_spawner::spawn(fut);
} Try / catch
// only useful in tests/process boundaries
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
any_spawner::spawn(async {});
})).err().map(|p| eprintln!("spawn before executor init: {:?}", p)); Prevention
- Install the global executor at program/test start.
- Search the codebase for Executor::spawn call sites and verify each runs after init.
- Run debug builds in CI to catch this early with the caller info.
When it happens
Trigger: Any Executor::spawn call while no global executor is set (set_executor never called), compiled with debug_assertions and without the tracing feature.
Common situations: Unit tests that spawn tasks but never init an executor; early code running before app bootstrap; feature-flag changes that disabled the executor setup path.
Related errors
- At {caller}, tried to spawn a Future with Executor::spawn_lo
- Executor::spawn called, but no global 'spawn' function is co
- Executor::spawn_local called, but no global 'spawn_local' fu
- called `unwrap_{variant}()` on a non-`{variant}` variant of
- Failed to find the route {path} requested by the user. This
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/4894c36f18271079.
Report an issue: GitHub.