rust-lang/rust-analyzer · critical

failed to spawn thread

Error message

failed to spawn thread

What it means

stdx::thread::spawn creates a named thread with the configured stack size and intent, and panics if the OS refuses to spawn it (std::thread::Builder::spawn returns Err, typically ResourceTemporarilyUnavailable or PermDenied). The doc comment explicitly states it panics on failure — threads are considered essential in rust-analyzer.

Source

Thrown at crates/stdx/src/thread.rs:34

//! and every entry point to creating a thread requires a [`ThreadIntent`] upfront.

use std::fmt;

mod intent;
mod pool;

pub use intent::ThreadIntent;
pub use pool::Pool;

/// # Panics
///
/// Panics if failed to spawn the thread.
pub fn spawn<F, T>(intent: ThreadIntent, name: String, f: F) -> JoinHandle<T>
where
    F: (FnOnce() -> T) + Send + 'static,
    T: Send + 'static,
{
    Builder::new(intent, name).spawn(f).expect("failed to spawn thread")
}

pub const DEFAULT_STACK_SIZE: usize = 16 * 1024 * 1024;

pub struct Builder {
    intent: ThreadIntent,
    inner: jod_thread::Builder,
    allow_leak: bool,
}

impl Builder {
    #[must_use]
    pub fn new(intent: ThreadIntent, name: impl Into<String>) -> Self {
        Self {
            intent,
            inner: jod_thread::Builder::new().name(name.into()).stack_size(DEFAULT_STACK_SIZE),
            allow_leak: false,
        }

View on GitHub (pinned to e8f7e90aa3)

Solutions

  1. Raise the process/thread limit: check `ulimit -u`, container pids limit (docker --pids-limit, Kubernetes pod pids), and increase it.
  2. Find and fix thread leaks in the application (threads spawned per request/task without joining).
  3. Reduce default stack size (stdx::thread::Builder stack size, default 16MiB) if memory-bound spawning fails.
  4. Free system resources (memory pressure, other processes) or restart the editor/LSP session.

Example fix

// before
stdx::thread::spawn(ThreadIntent::Worker, name, closure); // panics if spawn fails
// after
match stdx::thread::Builder::new(ThreadIntent::Worker, name).spawn(closure) {
    Ok(handle) => handle,
    Err(err) => { log::error!("thread spawn failed: {err}"); return; } // graceful fallback
}
Defensive patterns

Strategy: fallback

Try / catch

match stdx::thread::Builder::new(intent, name).spawn(f) {
    Ok(h) => h,
    Err(e) => { log::error!("spawn failed: {e}"); /* handle degraded mode */ }
}

Prevention

When it happens

Trigger: Calling stdx::thread::spawn when the process has exhausted thread resources: hitting RLIMIT_NPROC / pthread_create EAGAIN, too many threads already running, or insufficient memory for the 16MiB default stack.

Common situations: Long-running rust-analyzer sessions leaking threads; containerized environments (Docker/K8s) with low pids limits (e.g. pids.max); heavily loaded CI machines; spawning many parallel tasks without backpressure.

Related errors


AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03). Data as JSON: /api/errors/3637933c82f2f3e3. Report an issue: GitHub.