leptos-rs/leptos · critical
could not create futures executor ThreadPool
Error message
could not create futures executor ThreadPool
What it means
This panic comes from lazily initializing the global futures-executor ThreadPool inside `init_futures_executor` (any_spawner). `futures::executor::ThreadPool::new()` returns a Result and fails only when the underlying thread pool builder cannot spawn any worker threads (typically when `ThreadPoolBuilder::build()` hits an OS-level thread creation failure). any_spawner wraps this in `.expect`, so pool creation failure aborts the process on the first spawned task.
Source
Thrown at any_spawner/src/lib.rs:266
pub fn init_futures_executor() -> Result<(), ExecutorError> {
use futures::{
executor::{LocalPool, LocalSpawner, ThreadPool},
task::{LocalSpawnExt, SpawnExt},
};
use std::cell::RefCell;
// Keep the lazy-init ThreadPool and thread-local LocalPool for spawn_local impl
static THREAD_POOL: OnceLock<ThreadPool> = OnceLock::new();
thread_local! {
static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
// SPAWNER is derived from LOCAL_POOL, keep it for efficiency inside the closure
static SPAWNER: LocalSpawner = LOCAL_POOL.with(|pool| pool.borrow().spawner());
}
fn get_thread_pool() -> &'static ThreadPool {
THREAD_POOL.get_or_init(|| {
ThreadPool::new()
.expect("could not create futures executor ThreadPool")
})
}
let executor_impl = ExecutorFns {
spawn: |fut| {
get_thread_pool()
.spawn(fut)
.expect("failed to spawn future on ThreadPool");
},
spawn_local: |fut| {
// Use the thread_local SPAWNER derived from LOCAL_POOL
SPAWNER.with(|spawner| {
spawner
.spawn_local(fut)
.expect("failed to spawn local future");
});
},
poll_local: || {View on GitHub (pinned to 32d20f6c9d)
Solutions
- Raise the thread/process limit (ulimit -u, container pids cgroup) and free memory, then restart the application
- Ensure exactly one executor init and that another executor (tokio, async-executor, glib) is available; call `init_tokio`/`init_async_executor` instead of `init_futures_executor` on thread-restricted platforms
- Wrap pool creation context: run the app in an environment where `std::thread::Builder::new().spawn()` succeeds (verify with a small probe before bootstrapping)
- Pin/upgrade any_spawner and futures-executor versions so ThreadPoolBuilder configuration matches your runtime
Example fix
// before
any_spawner::executor::init_futures_executor().expect("init executor");
// after
#[cfg(feature = "tokio")]
any_spawner::executor::init_tokio().expect("init tokio executor");
#[cfg(not(feature = "tokio"))]
any_spawner::executor::init_futures_executor().expect("init futures executor"); Defensive patterns
Strategy: validation
Validate before calling
fn can_spawn_thread() -> bool {
std::thread::Builder::new()
.name("probe".into())
.spawn(|| {})
.map(|h| { let _ = h.join(); true })
.unwrap_or(false)
}
assert!(can_spawn_thread(), "thread creation unavailable; raise ulimit/pids limit or use another executor"); Try / catch
// init itself returns Result; only pool creation inside panics
if let Err(any_spawner::ExecutorError::AlreadySet) = any_spawner::executor::init_futures_executor() {
// already initialized elsewhere: fine
}
// guard the environment first (validationCode) since failure here panics Prevention
- Probe thread-creation ability at startup before choosing the futures executor
- Raise ulimit -u / container pids limits for thread-hungry deployments
- Prefer runtime-backed executors (tokio, async-executor) in containers and serverless
- Initialize the executor exactly once, early, in a controlled environment
When it happens
Trigger: Calling `any_spawner::_executor::init_futures_executor()` (directly or via Leptos' platform bootstrap) and then spawning the first future, on a system where thread creation fails: thread/process rlimit exhausted (RLIMIT_NPROC), memory exhaustion, restricted container/seccomp sandbox forbidding clone/pthread_create, or a heavily cgroup-limited environment.
Common situations: Running in minimal Docker containers or Kubernetes pods with low pids limits (e.g. pids.max), serverless/WASM-adjacent or CI sandboxes that disallow spawning threads, machines that have hit `ulimit -u`, or memory-starved hosts where the futures ThreadPool builder cannot allocate its threads.
Related errors
- failed to spawn future on ThreadPool
- Unsupported server function HTTP method: {method:?}
- {}
- Reading from a LocalResource outside Suspense in `ssr` mode
- at {location}, the `sandboxed-arenas` feature is active, but
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/4011e9d62523cdb6.
Report an issue: GitHub.