elkowar/eww · error

Failed to initialize tokio runtime for script var handlers

Error message

Failed to initialize tokio runtime for script var handlers

What it means

The script-var handler spawns a background thread that builds a multi-thread tokio runtime; if runtime construction fails, the `expect` panics inside that thread with this message. Without this runtime, poll and listen script vars cannot be processed.

Solutions

  1. Enable the required tokio features in Cargo.toml (`features = ["full"]` or at least `rt-multi-thread`, `macros`, `time`, `process`).
  2. Raise thread/process limits (ulimit -u) or relax container restrictions if worker-thread spawning fails.
  3. Check platform support for the multi-thread runtime.

Example fix

// Cargo.toml before
tokio = { version = "1", features = ["rt"] }
// after
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "process"] }
Defensive patterns

Strategy: try-catch

Validate before calling

// compile-time: tokio = { features = ["rt-multi-thread", "macros", "time", "process"] }

Try / catch

let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build();
if let Err(e) = rt { eprintln!("script-var handler disabled: {e}"); return; }

Prevention

When it happens

Trigger: Calling `ScriptVarHandler::init` when `Builder::new_multi_thread().enable_all().build()` returns an Err on the spawned thread.

Common situations: Tokio compiled without multi-thread scheduler or driver features; systems where thread/worker creation is restricted (ulimit, containers).


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

Appendix: source

Thrown at crates/eww/src/script_var_handler.rs:34

use tokio::{
    io::{AsyncBufReadExt, BufReader},
    sync::mpsc::UnboundedSender,
};
use tokio_util::sync::CancellationToken;
use yuck::config::script_var_definition::{ListenScriptVar, PollScriptVar, ScriptVarDefinition, VarSource};

/// Initialize the script var handler, and return a handle to that handler, which can be used to control
/// the script var execution.
pub fn init(evt_send: UnboundedSender<DaemonCommand>) -> ScriptVarHandlerHandle {
    let (msg_send, mut msg_recv) = tokio::sync::mpsc::unbounded_channel();
    let thread_handle = std::thread::Builder::new()
        .name("outer-script-var-handler".to_string())
        .spawn(move || {
            let rt = tokio::runtime::Builder::new_multi_thread()
                .enable_all()
                .thread_name("script-var-handler")
                .build()
                .expect("Failed to initialize tokio runtime for script var handlers");
            rt.block_on(async {
                let _: Result<_> = async {
                    let mut handler = ScriptVarHandler {
                        listen_handler: ListenVarHandler::new(evt_send.clone())?,
                        poll_handler: PollVarHandler::new(evt_send)?,
                    };
                    crate::loop_select_exiting! {
                        Some(msg) = msg_recv.recv() => match msg {
                            ScriptVarHandlerMsg::AddVar(var) => {
                                handler.add(var).await;
                            }
                            ScriptVarHandlerMsg::Stop(name) => {
                                handler.stop_for_variable(&name).await?;
                            }
                            ScriptVarHandlerMsg::StopAll => {
                                handler.stop_all().await;
                                break;
                            }

View on GitHub (pinned to 48f5aa8b37)