{"record":{"id":"6a84b8bf4c7d6431","repo":"leptos-rs/leptos","slug":"failed-to-spawn-local-future","errorCode":null,"errorMessage":"failed to spawn local future","messagePattern":"failed to spawn local future","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"any_spawner/src/lib.rs","lineNumber":281,"sourceCode":"        fn get_thread_pool() -> &'static ThreadPool {\n            THREAD_POOL.get_or_init(|| {\n                ThreadPool::new()\n                    .expect(\"could not create futures executor ThreadPool\")\n            })\n        }\n\n        let executor_impl = ExecutorFns {\n            spawn: |fut| {\n                get_thread_pool()\n                    .spawn(fut)\n                    .expect(\"failed to spawn future on ThreadPool\");\n            },\n            spawn_local: |fut| {\n                // Use the thread_local SPAWNER derived from LOCAL_POOL\n                SPAWNER.with(|spawner| {\n                    spawner\n                        .spawn_local(fut)\n                        .expect(\"failed to spawn local future\");\n                });\n            },\n            poll_local: || {\n                // Use the thread_local LOCAL_POOL\n                LOCAL_POOL.with(|pool| {\n                    // Use try_borrow_mut to prevent panic during re-entrant calls\n                    if let Ok(mut pool) = pool.try_borrow_mut() {\n                        pool.run_until_stalled();\n                    }\n                    // If already borrowed, we're likely in a nested poll, so do nothing.\n                });\n            },\n        };\n\n        EXECUTOR_FNS\n            .set(executor_impl)\n            .map_err(|_| ExecutorError::AlreadySet)\n    }","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/any_spawner/src/lib.rs#L263-L299","documentation":"Panics when `LocalSpawner::spawn_local(fut)` on the thread-local `LocalPool` returns Err. The futures LocalPool spawn fails when the spawner's pool has been dropped or is no longer able to accept tasks (e.g. the pool handle's inner state was consumed/closed). any_spawner stores the spawner in a thread_local and `.expect()`s on the result, so any failure panics at the spawn site.","triggerScenarios":"Calling `any_spawner::executor::spawn_local(...)` (used by Leptos for local reactive tasks) on a thread whose LocalPool spawner can no longer accept tasks — most notably across `fork()` without exec where thread-locals/runtime state is broken, or when spawning after pool teardown/shutdown.","commonSituations":"Applications that fork after initializing the executor (e.g. daemonization) and then spawn local tasks in the child; spawning during shutdown; using spawn_local from a thread other than where polling was expected after re-initialization attempts.","solutions":["Do not fork after calling init_futures_executor; initialize the executor after any fork (post-fork in the child, call init again only if EXECUTOR_FNS was never set)","Use `init_tokio`/`init_async_executor` and their local-set equivalents on runtimes that support spawn_local safely across your process model","Ensure executor init happens once per process and only on threads that will run the local pool","Wrap spawn_local calls behind your own guard that checks the executor is live before spawning"],"exampleFix":"// before\n// fork() first, then init and spawn_local\nlet child = unsafe { libc::fork() };\nany_spawner::executor::init_futures_executor().unwrap();\n// after\nany_spawner::executor::init_futures_executor().unwrap(); // init BEFORE any fork\n// or after fork, re-exec the process instead of continuing in the child","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    any_spawner::executor::spawn_local(async { /* task */ });\n}));\nif result.is_err() {\n    eprintln!(\"spawn_local failed: local pool unavailable on this thread\");\n}","preventionTips":["Never fork() after initializing the executor; init after fork or re-exec","Initialize the executor once at process start and keep it alive for the process lifetime","On runtimes with local-set support, prefer tokio's LocalSet-backed init over the futures LocalPool","Keep spawn_local calls on threads that participate in the same process init"],"tags":["rust","local-pool","spawn-local","panic"],"backgroundTag":"thread-spawn-failed","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}