{"record":{"id":"77965f466fe85ca0","repo":"LGUG2Z/komorebi","slug":"could-not-subscribe-to-komorebi-notifications","errorCode":null,"errorMessage":"could not subscribe to komorebi notifications","messagePattern":"could not subscribe to komorebi notifications","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"komorebi-bar/src/main.rs","lineNumber":350,"sourceCode":"\n    eframe::run_native(\n        \"komorebi-bar\",\n        native_options,\n        Box::new(|cc| {\n            let ctx_repainter = cc.egui_ctx.clone();\n            std::thread::spawn(move || loop {\n                std::thread::sleep(Duration::from_secs(1));\n                ctx_repainter.request_repaint();\n            });\n\n            let ctx_komorebi = cc.egui_ctx.clone();\n            std::thread::spawn(move || {\n                let subscriber_name = format!(\"komorebi-bar-{}\", random_word::get(random_word::Lang::En));\n\n                let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {\n                    filter_state_changes: true,\n                })\n                    .expect(\"could not subscribe to komorebi notifications\");\n\n                tracing::info!(\"subscribed to komorebi notifications: \\\"{}\\\"\", subscriber_name);\n\n                for client in listener.incoming() {\n                    match client {\n                        Ok(subscription) => {\n                            match subscription.set_read_timeout(Some(Duration::from_secs(1))) {\n                                Ok(()) => {}\n                                Err(error) => tracing::error!(\"{}\", error),\n                            }\n                            let mut buffer = Vec::new();\n                            let mut reader = BufReader::new(subscription);\n\n                            // this is when we know a shutdown has been sent\n                            if matches!(reader.read_to_end(&mut buffer), Ok(0)) {\n                                tracing::info!(\"disconnected from komorebi\");\n\n                                // keep trying to reconnect to komorebi","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/LGUG2Z/komorebi/blob/e0709f02bfae4e503bf4640f58ee75ecbbfdbb97/komorebi-bar/src/main.rs#L332-L368","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure komorebi is running and healthy before launching komorebi-bar (start bar after komorebi, or add a wait/retry loop around subscribe_with_options)","Check that no stale komorebi subscription sockets/named pipes exist from a previous crashed session; restart komorebi to recreate them","Verify komorebi and komorebi-bar versions match (komorebi-client talks a specific protocol); update both together","Run komorebi-bar in the same user session as komorebi so the pipe is accessible (no cross-session/permission mismatch)","If appropriate for the bar, replace expect with a loop that retries the subscription after a delay and logs the failure instead of panicking"],"exampleFix":"// before\nlet listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {\n    filter_state_changes: true,\n})\n    .expect(\"could not subscribe to komorebi notifications\");\n// after\nlet listener = loop {\n    match komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {\n        filter_state_changes: true,\n    }) {\n        Ok(l) => break l,\n        Err(e) => {\n            tracing::warn!(\"could not subscribe to komorebi notifications ({e}); retrying in 2s\");\n            std::thread::sleep(std::time::Duration::from_secs(2));\n        }\n    }\n};","handlingStrategy":"retry","validationCode":"// Rust: check komorebi socket reachability before subscribing\nfn komorebi_running() -> bool {\n    std::process::Command::new(\"tasklist\")\n        .args([\"/FI\", \"IMAGENAME eq komorebi.exe\"])\n        .output()\n        .map(|o| String::from_utf8_lossy(&o.stdout).contains(\"komorebi.exe\"))\n        .unwrap_or(false)\n}\nif !komorebi_running() { eprintln!(\"komorebi not running; defer bar start\"); }","typeGuard":null,"tryCatchPattern":"loop {\n    match komorebi_client::subscribe_with_options(&name, opts) {\n        Ok(l) => break l,\n        Err(e) => { log::warn!(\"subscribe failed: {e}\"); std::thread::sleep(Duration::from_secs(2)); }\n    }\n}","preventionTips":["Start komorebi-bar only after komorebi is fully running (startup dependency ordering)","Wrap subscription in a bounded retry with backoff instead of expect","Pin komorebi and komorebi-bar to matching versions","Clean up stale named pipes after crashes before restarting"],"tags":["windows","named-pipe","ipc","rust","panic"],"backgroundTag":"connection-refused","analyzedSha":"e0709f02bfae4e503bf4640f58ee75ecbbfdbb97","analyzedAt":"2026-09-06T07:08:05.107Z","contentChangedAt":"2026-09-06T07:08:05.107Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}