espanso/espanso · error
Unable to spawn worker monitor thread
Error message
Unable to spawn worker monitor thread
What it means
After spawning the worker child, spawn_worker starts a 'worker-status-monitor' thread via std::thread::Builder::new().spawn to watch the child and forward its exit code. If the thread cannot be created, the expect panics with this message, leaving the worker unmonitored.
Source
Thrown at espanso/src/cli/daemon/mod.rs:325
std::thread::Builder::new()
.name("worker-status-monitor".to_string())
.spawn(move || {
let result = child.wait();
if let Ok(status) = result {
if let Some(code) = status.code() {
if code != WORKER_SUCCESS {
exit_notify
.send(code)
.expect("unable to forward worker exit code");
}
} else {
exit_notify
.send(WORKER_ERROR_EXIT_NO_CODE)
.expect("unable to forward worker exit code");
}
}
})
.expect("Unable to spawn worker monitor thread");
}
fn restart_worker(
paths: &Paths,
paths_overrides: &PathsOverrides,
exit_notify: Sender<i32>,
start_reason: Option<String>,
) {
match create_ipc_client_to_worker(&paths.runtime) {
Ok(mut worker_ipc) => {
if let Err(err) = worker_ipc.send_async(IPCEvent::Exit) {
error!("unable to send termination signal to worker process: {err}");
}
}
Err(err) => {
error!("could not establish IPC connection with worker: {err}");
}
}View on GitHub (pinned to e6c3736675)
Solutions
- Check and raise thread/process limits (ulimit -u, container pids limit)
- Free memory or reduce concurrent threads in the environment
- Confirm the process is not leaking threads that exhausted the limit
- Convert the expect into error handling that retries thread creation or exits gracefully
Example fix
// before
.expect("Unable to spawn worker monitor thread");
// after
if let Err(err) = std::thread::Builder::new()
.name("worker-status-monitor".to_string())
.spawn(move || { /* monitor loop */ })
{
error!("Unable to spawn worker monitor thread: {err}");
} Defensive patterns
Strategy: try-catch
Try / catch
match std::thread::Builder::new().name("worker-status-monitor".to_string()).spawn(move || { /* ... */ }) {
Ok(handle) => { /* keep handle */ },
Err(err) => { error!("monitor thread spawn failed: {err}"); }
} Prevention
- Avoid exhausting thread limits (check pids cgroup, ulimit -u)
- Monitor memory pressure; thread stacks need allocation
- Reduce long-lived threads in the host process
When it happens
Trigger: std::thread::Builder::spawn returns Err, i.e. the OS refuses to allocate a new thread — thread-count limits (RLIMIT_NPROC / cgroup pids), out of memory for the new stack, or a security policy blocking thread creation.
Common situations: Systems at their max thread/process limit, containers with low pids.cgroup limits, severe memory exhaustion, hardened sandboxes restricting clone().
Related errors
- git command exited with non-zero status: {}
- unable to wait for troubleshooter
- no troubleshoot guard found
- service registration returned non-zero exit code
- unable to obtain espanso executable location
AI-assisted analysis of espanso/espanso@e6c3736675 (2026-09-06).
Data as JSON: /api/errors/6059fefd741f2a83.
Report an issue: GitHub.