espanso/espanso · critical

unable to run main eventloop

Error message

unable to run main eventloop

What it means

eventloop.run() starts the main UI event loop, dispatching every UI event to the engine through a channel; this expect panics if run returns Err. Once this fails the worker cannot process events at all and must terminate.

Source

Thrown at espanso/src/cli/worker/mod.rs:168

    // terminate the worker if the daemon terminates
    // This is needed to avoid "dangling" worker processes
    // if the daemon crashes or is forcefully terminated.
    if cli_args.is_present("monitor-daemon") {
        daemon_monitor::initialize_and_spawn(&paths.runtime, engine_exit_notify)
            .expect("unable to initialize daemon monitor thread");
    }

    secure_input::initialize_and_spawn(engine_secure_input_sender)
        .expect("unable to initialize secure input watcher");

    eventloop
        .run(Box::new(move |event| {
            if let Err(error) = engine_ui_event_sender.send(event) {
                error!("unable to send UIEvent to engine: {error}");
                panic!("broken UI->Engine channel");
            }
        }))
        .expect("unable to run main eventloop");

    info!("waiting for engine exit mode...");
    match engine_handle.join() {
        Ok(mode) => match mode {
            ExitMode::Exit => {
                info!("exiting worker process...");
                WORKER_SUCCESS
            }
            ExitMode::ExitAllProcesses => {
                info!("exiting worker process and daemon...");
                WORKER_EXIT_ALL_PROCESSES
            }
            ExitMode::RestartWorker => {
                info!("exiting worker (to be restarted)");
                WORKER_RESTART
            }
        },
        Err(err) => {

View on GitHub (pinned to e6c3736675)

Solutions

  1. Restart espanso after the display session is stable again (`espanso restart`).
  2. Check whether the engine thread died first (broken UI->Engine channel panic) and fix the root engine failure seen earlier in logs.
  3. Avoid restarting the display manager/compositor while espanso runs; stop espanso first.
  4. Inspect platform logs for X11/Wayland disconnection errors and fix the session stability issue.
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(err) = eventloop.run(Box::new(move |event| { ... })) {
    error!("main eventloop terminated: {err}");
    // trigger supervised restart via the daemon
    std::process::exit(1);
}

Prevention

When it happens

Trigger: The platform event loop's run() returns an error — display connection lost mid-run (X server terminated, Wayland compositor restart), the UI subsystem hit a fatal error while pumping events, or the callback panicked (broken UI->Engine channel) propagating failure.

Common situations: Logging out or restarting the display server while espanso runs, X11/Wayland session crashes, desktop environment switching, or the engine thread having exited causing the send in the callback to fail and panic.

Related errors


AI-assisted analysis of espanso/espanso@e6c3736675 (2026-09-06). Data as JSON: /api/errors/f2c042e379aa2e45. Report an issue: GitHub.