{"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":"error","filePath":"crates/atuin-nucleo/src/worker.rs","lineNumber":81,"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":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin-nucleo/src/worker.rs#L63-L99","documentation":"atuin-nucleo (Atuin's nucleo fork) builds its matcher worker pool with rayon, sized by the worker_threads argument or std::thread::available_parallelism. rayon's ThreadPoolBuilder::build returns Err when worker threads cannot be spawned — thread/process limits or memory exhaustion — and Worker::new expects the Result, panicking with 'creating threadpool failed' when search starts.","triggerScenarios":"Constructing the matcher (atuin search / interactive TUI startup) when thread creation fails: cgroup pids.max reached, RLIMIT_NPROC (ulimit -u) exhausted, systemd TasksMax hit, or out of memory to map thread stacks. Note rayon treats num_threads=0 as 'use default', so Some(0) is not the trigger.","commonSituations":"Containers with low --pids-limit; shared machines where the user hits nproc; memory-constrained environments where default 2MB thread stacks cannot be allocated.","solutions":["Raise thread/process limits: docker --pids-limit, systemd TasksMax, ulimit -u","Reduce parallelism: configure fewer matcher worker threads if your embedding exposes the knob","Free memory or lower thread stack size so rayon workers can spawn"],"exampleFix":"# before\ndocker run --pids-limit 64 ...\n\n# after\ndocker run --pids-limit 512 ...","handlingStrategy":"validation","validationCode":"fn can_spawn_threads(n: usize) -> bool {\n    let handles: Vec<_> = (0..n).map(|_| std::thread::spawn(|| ())).collect();\n    handles.into_iter().all(|h| h.join().is_ok())\n}\n\nlet desired = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1);\nassert!(can_spawn_threads(desired), \"thread budget too low for the matcher pool\");","typeGuard":null,"tryCatchPattern":"let engine = std::panic::catch_unwind(|| {\n    atuin_nucleo::Nucleo::<atuin_history::History>::new(config, &notify, cols)\n});\n// on Err: retry with a smaller worker budget or surface a clear resource error","preventionTips":["Set generous pids limits (--pids-limit, TasksMax, ulimit -u) where search runs","Cap matcher worker threads explicitly in constrained environments","Check memory headroom: each rayon worker maps a thread stack"],"tags":["rayon","threads","threadpool","resource-limits","matcher","panic"],"backgroundTag":"thread-spawn-failed","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}