{"record":{"id":"8341ecaff3290fdf","repo":"pola-rs/polars","slug":"could-not-spawn-threads","errorCode":null,"errorMessage":"could not spawn threads","messagePattern":"could not spawn threads","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/polars-core/src/runtime.rs","lineNumber":199,"sourceCode":"            match out.unwrap() {\n                Ok(v) => v,\n                Err(panic) => std::panic::resume_unwind(panic),\n            }\n        } else {\n            f()\n        }\n    }\n}\n\n// this is re-exported in utils for polars child crates\n#[cfg(not(target_family = \"wasm\"))] // only use this on non wasm targets\npub static THREAD_POOL: LazyLock<ThreadPool> = LazyLock::new(|| {\n    let thread_name = std::env::var(\"POLARS_THREAD_NAME\").unwrap_or_else(|_| \"polars\".to_string());\n    ThreadPoolBuilder::new()\n        .num_threads(polars_config::config().max_threads())\n        .thread_name(move |i| format!(\"{thread_name}-{i}\"))\n        .build()\n        .expect(\"could not spawn threads\")\n});\n\n#[cfg(all(target_os = \"emscripten\", target_family = \"wasm\"))] // Use 1 rayon thread on emscripten\npub static THREAD_POOL: LazyLock<ThreadPool> = LazyLock::new(|| {\n    ThreadPoolBuilder::new()\n        .num_threads(1)\n        .use_current_thread()\n        .build()\n        .expect(\"could not create pool\")\n});\n\npub use polars_async::ASYNC;\n","sourceCodeStart":181,"sourceCodeEnd":212,"githubUrl":"https://github.com/pola-rs/polars/blob/9b5d73fd00236295624374b075d16b1fe6ec6df9/crates/polars-core/src/runtime.rs#L181-L212","documentation":"polars lazily builds a global rayon thread pool sized from POLARS_MAX_THREADS / the config max_threads on first parallel use. If the OS refuses to create that many threads (process thread limit, cgroup pids limit, memory exhaustion), ThreadPoolBuilder::build fails and LazyLock panics 'could not spawn threads'.","triggerScenarios":"The first parallel operation in the process (any group_by, join, or parallel iteration) in an environment that caps thread creation: ulimit -u reached, container pids.max exhausted, RLIMIT_NPROC, or POLARS_MAX_THREADS set above what the environment allows.","commonSituations":"Containers/Kubernetes with low pids limits; CI sandboxes; servers that already host many threads (async runtimes, other rayon pools); POLARS_MAX_THREADS misconfigured to a huge value; embedder apps that fork after polars loads.","solutions":["Cap polars' thread count to fit the environment: export POLARS_MAX_THREADS=4 (or set it programmatically before first use)","Raise the OS limits: ulimit -u, container pids.max / --pids-limit, or free memory","Trigger pool initialization early (e.g. POLARS_MAX_THREADS set at process start) so the failure surfaces at a controlled point"],"exampleFix":"# before\npython -c \"import polars as pl; pl.len()\"  # panics if thread limit hit\n\n# after\nexport POLARS_MAX_THREADS=4\npython -c \"import polars as pl; pl.len()\"","handlingStrategy":"validation","validationCode":"# set before importing/first using polars\nimport os\nos.environ[\"POLARS_MAX_THREADS\"] = \"4\"\nimport polars as pl","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set POLARS_MAX_THREADS explicitly to a value well under the environment's thread limit","Check ulimit -u and container pids.max when deploying polars in constrained environments","Initialize the pool deliberately at startup so failures surface during boot, not mid-query"],"tags":["polars","rayon","thread-pool","environment","panic","resource-limit"],"backgroundTag":"thread-creation-failed","analyzedSha":"9b5d73fd00236295624374b075d16b1fe6ec6df9","analyzedAt":"2026-08-19T12:15:06.350Z","contentChangedAt":"2026-08-19T12:15:06.350Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}