{"record":{"id":"363a97d08893a6cf","repo":"mgth/LittleBigMouse","slug":"failed-to-start-per-user-local-ipc-error","errorCode":null,"errorMessage":"failed to start per-user local IPC: {error}","messagePattern":"failed to start per-user local IPC: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"rust/crates/lbm-hook/src/main.rs","lineNumber":29,"sourceCode":"use littlebigmouse_hook::{daemon, hook, ipc, platform};\n\nfn main() {\n    platform::init();\n\n    let shared: &'static Shared = SHARED.get_or_init(Shared::new);\n\n    // main() is the event-loop thread; record it before the server can accept a\n    // command that would signal it.\n    hook::register_main_thread(shared);\n\n    // `LBM_HOOK_ENDPOINT` overrides the per-session pipe/socket path, enabling\n    // side-by-side testing next to a running daemon (successor of the old\n    // LBM_HOOK_PORT override).\n    let (server, endpoint) = match std::env::var(\"LBM_HOOK_ENDPOINT\") {\n        Ok(endpoint) => ipc::server::start_with_endpoint(shared, endpoint),\n        Err(_) => ipc::server::start(shared),\n    }\n    .unwrap_or_else(|error| panic!(\"failed to start per-user local IPC: {error}\"));\n    let _ = shared.server.set(server);\n\n    eprintln!(\"[LittleBigMouse.Hook] listening on {endpoint}\");\n\n    // C++ Program.cpp: UI mode (wait for socket commands) when launched by the UI\n    // (parent path contains \"LittleBigMouse\"); otherwise standalone — load the\n    // last saved layout and start hooking. `LBM_HOOK_UI` forces UI mode for tests.\n    let ui_mode = std::env::var_os(\"LBM_HOOK_UI\").is_some()\n        || platform::process::parent_process_path()\n            .map(|p| p.contains(\"LittleBigMouse\"))\n            .unwrap_or(false);\n\n    if !ui_mode {\n        if let Some(path) = platform::paths::lbm_data_file(\"Current.xml\") {\n            eprintln!(\n                \"[LittleBigMouse.Hook] standalone mode: loading {}\",\n                path.display()\n            );","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/rust/crates/lbm-hook/src/main.rs#L11-L47","documentation":"The lbm-hook Rust daemon's main() starts its per-user local IPC server (ipc::server::start, or start_with_endpoint when LBM_HOOK_ENDPOINT is set) before entering its listen loop. If the server cannot bind/start, the Result is unwrapped with a panic! carrying the underlying IPC error, aborting the hook process at startup.","triggerScenarios":"Running the hook binary when the IPC socket/endpoint cannot be created or bound — a stale socket file at the default endpoint path, LBM_HOOK_ENDPOINT set to an unusable path or address, a permission problem in the runtime directory, or another (leftover) process already holding the endpoint.","commonSituations":"A previous crashed hook instance left a stale socket file; side-by-side testing with LBM_HOOK_ENDPOINT pointing at a directory that does not exist or is not writable; running under a sandbox (Flatpak/systemd) without access to the default runtime dir; two hook instances racing on the same endpoint.","solutions":["Remove the stale socket/endpoint file (or choose a fresh endpoint) and restart the hook.","If LBM_HOOK_ENDPOINT is set, verify it points to an existing, writable location not already in use; unset it to fall back to the default per-user endpoint.","Ensure the per-user runtime directory (XDG runtime dir / tmp equivalent) exists and is writable by the user running the hook.","Kill any leftover hook/daemon process still bound to the endpoint before relaunching."],"exampleFix":"// before\nLBM_HOOK_ENDPOINT=/run/user/1000/lbm-test ./lbm-hook // dir missing -> panic\n// after\nmkdir -p /run/user/1000/lbm-test && rm -f /run/user/1000/lbm.sock && ./lbm-hook","handlingStrategy":"validation","validationCode":"// before launching the hook\nif let Ok(ep) = std::env::var(\"LBM_HOOK_ENDPOINT\") {\n    let p = std::path::Path::new(&ep);\n    if p.exists() { eprintln!(\"endpoint {} already exists (stale socket?) — remove or change it\", ep); }\n    else if let Some(dir) = p.parent() {\n        if !dir.is_dir() { eprintln!(\"endpoint parent {} does not exist\", dir.display()); }\n    }\n}","typeGuard":"fn endpoint_usable(ep: &str) -> bool {\n    let p = std::path::Path::new(ep);\n    !p.exists() && p.parent().map(|d| d.is_dir()).unwrap_or(false)\n}","tryCatchPattern":"match std::panic::catch_unwind(|| start_hook(shared)) {\n    Ok(()) => {},\n    Err(_) => eprintln!(\"[LittleBigMouse.Hook] IPC startup failed: remove stale socket or free the endpoint, then retry\"),\n}","preventionTips":["Clean up stale socket files on shutdown (and at startup) so a crashed instance does not block the next one.","Only set LBM_HOOK_ENDPOINT for side-by-side testing, and point it at a dedicated writable directory.","Ensure the per-user runtime directory (XDG_RUNTIME_DIR) exists and has correct ownership before launch.","Adopt a single-instance lock or PID check so two hook processes never race for the same endpoint."],"tags":["rust","ipc","startup-failure","socket-bind"],"backgroundTag":"address-already-in-use","analyzedSha":"7a42f01d47d99d223b8ee33ba4019af82adf1c48","analyzedAt":"2026-09-16T00:35:00.514Z","contentChangedAt":"2026-09-16T00:35:00.514Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}