elkowar/eww · error

Failed to start script-var-handler thread

Error message

Failed to start script-var-handler thread

What it means

`ScriptVarHandler::init` spawns the OS thread that hosts the handler runtime. If `std::thread::Builder::spawn` fails, the `expect` panics with this message. Without the thread, script variables (poll/listen) will not be evaluated, so eww aborts rather than run with a broken var system.

Solutions

  1. Raise thread limits: `ulimit -u unlimited` (or a higher value) for the eww process.
  2. Check sandbox/container policies that block thread creation and allow them.
  3. Free system resources / investigate memory pressure that prevents spawning threads.

Example fix

// before (systemd unit)
TasksMax=30
// after
TasksMax=infinity
Defensive patterns

Strategy: retry

Validate before calling

let ok = std::thread::available_parallelism().is_ok(); // thread env sanity check (approximate)

Try / catch

match std::thread::Builder::new().name("outer-script-var-handler".into()).spawn(work) {
    Ok(h) => h,
    Err(e) => { eprintln!("handler thread spawn failed: {e}"); return ...; }
}

Prevention

When it happens

Trigger: `ScriptVarHandler::init` when the OS refuses to spawn the "outer-script-var-handler" thread (resource exhaustion, thread limits, security restrictions).

Common situations: Hitting `ulimit -u` thread limits, running in restricted sandboxes/containers denying thread creation, low-memory conditions.


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

Appendix: source

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

                            ScriptVarHandlerMsg::AddVar(var) => {
                                handler.add(var).await;
                            }
                            ScriptVarHandlerMsg::Stop(name) => {
                                handler.stop_for_variable(&name).await?;
                            }
                            ScriptVarHandlerMsg::StopAll => {
                                handler.stop_all().await;
                                break;
                            }
                        },
                        else => break,
                    };
                    Ok(())
                }
                .await;
            })
        })
        .expect("Failed to start script-var-handler thread");
    ScriptVarHandlerHandle { msg_send, thread_handle }
}

/// Handle to the script-var handling system.
pub struct ScriptVarHandlerHandle {
    msg_send: UnboundedSender<ScriptVarHandlerMsg>,
    thread_handle: std::thread::JoinHandle<()>,
}

impl ScriptVarHandlerHandle {
    /// Add a new script-var that should be executed.
    /// This is idempodent, meaning that running a definition that already has a script_var attached which is running
    /// won't do anything.
    pub fn add(&self, script_var: ScriptVarDefinition) {
        crate::print_result_err!(
            "while forwarding instruction to script-var handler",
            self.msg_send.send(ScriptVarHandlerMsg::AddVar(script_var))
        );

View on GitHub (pinned to 48f5aa8b37)