{"record":{"id":"6fc63a5a01b242d9","repo":"atuinsh/atuin","slug":"creating-threadpool-failed","errorCode":null,"errorMessage":"creating threadpool failed","messagePattern":"creating threadpool failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/atuin-nucleo/src/worker.rs","lineNumber":82,"sourceCode":"    }\n\n    pub(crate) fn set_scorer(&mut self, scorer: Option<Scorer<T>>) {\n        self.scorer = scorer;\n    }\n\n    pub(crate) fn new(\n        worker_threads: Option<usize>,\n        config: Config,\n        notify: Arc<dyn Fn() + Sync + Send>,\n        cols: u32,\n    ) -> (ThreadPool, Self) {\n        let worker_threads = worker_threads\n            .unwrap_or_else(|| std::thread::available_parallelism().map_or(4, |it| it.get()));\n        let pool = rayon::ThreadPoolBuilder::new()\n            .thread_name(|i| format!(\"nucleo worker {i}\"))\n            .num_threads(worker_threads)\n            .build()\n            .expect(\"creating threadpool failed\");\n        let matchers = (0..worker_threads)\n            .map(|_| UnsafeCell::new(atuin_nucleo_matcher::Matcher::new(config.clone())))\n            .collect();\n        let worker = Worker {\n            running: false,\n            matchers: Matchers(matchers),\n            last_snapshot: 0,\n            matches: Vec::new(),\n            // just a placeholder\n            pattern: MultiPattern::new(cols as usize),\n            sort_results: true,\n            reverse_items: false,\n            canceled: Arc::new(AtomicBool::new(false)),\n            should_notify: Arc::new(AtomicBool::new(false)),\n            was_canceled: false,\n            notify,\n            items: Arc::new(boxcar::Vec::with_capacity(2 * 1024, cols)),\n            in_flight: Vec::with_capacity(64),","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/atuinsh/atuin/blob/15fe1318f1df51de604262eb50734c9883d48e7b/crates/atuin-nucleo/src/worker.rs#L64-L100","documentation":"`Worker::new` builds the rayon thread pool with `ThreadPoolBuilder::build().expect(\"creating threadpool failed\")`. `build()` returns Err when the configured number of OS threads cannot be spawned - thread/pid limits (RLIMIT_NPROC, cgroup pids.max), memory exhaustion, or a zero thread count. Because it panics at matcher startup, it takes the whole process down.","triggerScenarios":"Creating the matcher worker pool when the process is already at its thread limit (a thread leak elsewhere, nested rayon pools, a container `--pids-limit`); passing `Some(0)` as `worker_threads`.","commonSituations":"Containers/sandboxes with low pid limits; test harnesses spawning many nucleo instances in parallel; fork servers hitting RLIMIT_NPROC.","solutions":["Lower `worker_threads`, or pass `None` so it defaults to `available_parallelism()` (min 4)","Raise the process's thread/pid limits: `ulimit -u`, cgroup `pids.max`, container `--pids-limit`","Never pass `Some(0)`; validate the value before calling the matcher constructor","Fix thread leaks elsewhere in the process before starting the matcher"],"exampleFix":"// before\nlet (pool, worker) = Worker::new(Some(0), config, notify, cols); // invalid\n\n// after\nlet threads = std::thread::available_parallelism()\n    .map_or(4, |n| n.get())\n    .max(1);\nlet (pool, worker) = Worker::new(Some(threads), config, notify, cols);","handlingStrategy":"validation","validationCode":"// Validate thread budget before constructing the matcher\nlet requested = worker_threads.unwrap_or_else(|| {\n    std::thread::available_parallelism().map_or(4, |n| n.get())\n});\nif requested == 0 {\n    return Err(\"worker_threads must be >= 1\".into());\n}\n// sanity: leave room for the rest of the process\nif requested > 4 * std::thread::available_parallelism().map_or(4, |n| n.get()) {\n    return Err(\"worker_threads unreasonably high\".into());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass Some(0) as a thread count; treat it as invalid at your API boundary","Raise pid/thread limits (ulimit -u, cgroup pids.max, docker --pids-limit) before starting many workers","Fix thread leaks before instantiating nested thread pools; count live threads at startup"],"tags":["rust","rayon","threadpool","panic","resource-limits","nucleo"],"backgroundTag":"thread-creation-failed","analyzedSha":"15fe1318f1df51de604262eb50734c9883d48e7b","analyzedAt":"2026-08-19T08:56:57.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}