elkowar/eww · critical

Failed to initialize tokio runtime

Error message

Failed to initialize tokio runtime

What it means

tokio's multi-threaded runtime Builder::build() returned an Err, and eww unwraps it with expect. Runtime construction fails almost exclusively when the OS refuses to create the runtime's worker/blocking threads (thread spawn failure), e.g. due to resource limits.

Solutions

  1. Check and raise limits: `ulimit -u`, systemd `TasksMax=infinity` on the user unit, container pids cgroup limit.
  2. Free resources: kill leaked eww/zombie processes of the same user, or restart the session.
  3. Run eww with fewer competing processes, or in a container with raised limits.
  4. As a code-level guard, replace .expect with propagating the error so the daemon can log a clear message and exit gracefully.

Example fix

// before
let rt = tokio::runtime::Builder::new_multi_thread()
    .thread_name("main-async-runtime")
    .enable_all()
    .build()
    .expect("Failed to initialize tokio runtime");
// after
let rt = tokio::runtime::Builder::new_multi_thread()
    .thread_name("main-async-runtime")
    .enable_all()
    .worker_threads(2)
    .build()
    .map_err(|e| anyhow::anyhow!("Failed to initialize tokio runtime: {} (check RLIMIT_NPROC / TasksMax)", e))?;
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check resource headroom
let limits = rlimit::getrlimit(rlimit::Resource::NPROC).unwrap();
assert!(limits.0 > 64, "process/thread limit too low for tokio runtime");

Try / catch

match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
    Ok(rt) => /* proceed */,
    Err(e) => log::error!("runtime init failed: {} — check RLIMIT_NPROC/TasksMax", e),
}

Prevention

When it happens

Trigger: Calling init_async_part when the process has hit RLIMIT_NPROC, the system is out of memory or PIDs (threads are internally the same resource as processes on Linux), or running inside a container/pod with a low pids cgroup limit.

Common situations: Docker/Kubernetes pods with low pids.max, shared servers where the user already runs many threads, systemd units lacking TasksMax headroom, or memory exhaustion on small VPSes.

Related errors


AI-assisted analysis of elkowar/eww@48f5aa8b37 (2026-09-08). Data as JSON: /api/errors/02a667e21e965141. Report an issue: GitHub.

Appendix: source

Thrown at crates/eww/src/server.rs:169

fn reload_config_and_css(ui_send: &UnboundedSender<DaemonCommand>) -> Result<()> {
    let (daemon_resp_sender, mut daemon_resp_response) = daemon_response::create_pair();
    ui_send.send(DaemonCommand::ReloadConfigAndCss(daemon_resp_sender))?;
    tokio::spawn(async move {
        match daemon_resp_response.recv().await {
            Some(daemon_response::DaemonResponse::Success(_)) => log::info!("Reloaded config successfully"),
            Some(daemon_response::DaemonResponse::Failure(e)) => eprintln!("{}", e),
            None => log::error!("No response to reload configuration-reload request"),
        }
    });
    Ok(())
}

fn init_async_part(paths: EwwPaths, ui_send: UnboundedSender<app::DaemonCommand>) -> tokio::runtime::Handle {
    let rt = tokio::runtime::Builder::new_multi_thread()
        .thread_name("main-async-runtime")
        .enable_all()
        .build()
        .expect("Failed to initialize tokio runtime");
    let handle = rt.handle().clone();

    std::thread::Builder::new()
        .name("outer-main-async-runtime".to_string())
        .spawn(move || {
            rt.block_on(async {
                let filewatch_join_handle = {
                    let ui_send = ui_send.clone();
                    let paths = paths.clone();
                    tokio::spawn(async move { run_filewatch(paths.config_dir, ui_send).await })
                };

                let ipc_server_join_handle = {
                    let ui_send = ui_send.clone();
                    tokio::spawn(async move { ipc_server::run_server(ui_send, paths.get_ipc_socket_file()).await })
                };

                let forward_exit_to_app_handle = {

View on GitHub (pinned to 48f5aa8b37)