LGUG2Z/komorebi · critical

could not subscribe to komorebi notifications

Error message

could not subscribe to komorebi notifications

What it means

komorebi-client's subscribe_with_options connects to komorebi's named-pipe notification broker and returns a SocketListener. This panic fires when the client fails to create or connect the subscription socket, meaning the bar cannot receive window-manager state updates. It is an expect() in a spawned thread, so the whole process aborts when the handshake fails.

Source

Thrown at komorebi-bar/src/main.rs:350

    eframe::run_native(
        "komorebi-bar",
        native_options,
        Box::new(|cc| {
            let ctx_repainter = cc.egui_ctx.clone();
            std::thread::spawn(move || loop {
                std::thread::sleep(Duration::from_secs(1));
                ctx_repainter.request_repaint();
            });

            let ctx_komorebi = cc.egui_ctx.clone();
            std::thread::spawn(move || {
                let subscriber_name = format!("komorebi-bar-{}", random_word::get(random_word::Lang::En));

                let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {
                    filter_state_changes: true,
                })
                    .expect("could not subscribe to komorebi notifications");

                tracing::info!("subscribed to komorebi notifications: \"{}\"", subscriber_name);

                for client in listener.incoming() {
                    match client {
                        Ok(subscription) => {
                            match subscription.set_read_timeout(Some(Duration::from_secs(1))) {
                                Ok(()) => {}
                                Err(error) => tracing::error!("{}", error),
                            }
                            let mut buffer = Vec::new();
                            let mut reader = BufReader::new(subscription);

                            // this is when we know a shutdown has been sent
                            if matches!(reader.read_to_end(&mut buffer), Ok(0)) {
                                tracing::info!("disconnected from komorebi");

                                // keep trying to reconnect to komorebi

View on GitHub (pinned to e0709f02bf)

Solutions

  1. Ensure komorebi is running and healthy before launching komorebi-bar (start bar after komorebi, or add a wait/retry loop around subscribe_with_options)
  2. Check that no stale komorebi subscription sockets/named pipes exist from a previous crashed session; restart komorebi to recreate them
  3. Verify komorebi and komorebi-bar versions match (komorebi-client talks a specific protocol); update both together
  4. Run komorebi-bar in the same user session as komorebi so the pipe is accessible (no cross-session/permission mismatch)
  5. If appropriate for the bar, replace expect with a loop that retries the subscription after a delay and logs the failure instead of panicking

Example fix

// before
let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {
    filter_state_changes: true,
})
    .expect("could not subscribe to komorebi notifications");
// after
let listener = loop {
    match komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {
        filter_state_changes: true,
    }) {
        Ok(l) => break l,
        Err(e) => {
            tracing::warn!("could not subscribe to komorebi notifications ({e}); retrying in 2s");
            std::thread::sleep(std::time::Duration::from_secs(2));
        }
    }
};
Defensive patterns

Strategy: retry

Validate before calling

// Rust: check komorebi socket reachability before subscribing
fn komorebi_running() -> bool {
    std::process::Command::new("tasklist")
        .args(["/FI", "IMAGENAME eq komorebi.exe"])
        .output()
        .map(|o| String::from_utf8_lossy(&o.stdout).contains("komorebi.exe"))
        .unwrap_or(false)
}
if !komorebi_running() { eprintln!("komorebi not running; defer bar start"); }

Try / catch

loop {
    match komorebi_client::subscribe_with_options(&name, opts) {
        Ok(l) => break l,
        Err(e) => { log::warn!("subscribe failed: {e}"); std::thread::sleep(Duration::from_secs(2)); }
    }
}

Prevention

When it happens

Trigger: Calling komorebi_client::subscribe_with_options with SubscribeOptions { filter_state_changes: true } when the komorebi broker/socket is unreachable: komorebi is not running, the pipe path is wrong, the subscription name cannot be registered, or a previous subscriber left a stale socket.

Common situations: Starting komorebi-bar at login before komorebi has initialized its socket; komorebi crashed while the bar auto-restarts; running komorebi-bar outside a komorebi-managed session (e.g. testing on a machine without komorebi running); permission issues on the named pipe.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of LGUG2Z/komorebi@e0709f02bf (2026-09-06). Data as JSON: /api/errors/77965f466fe85ca0. Report an issue: GitHub.