mgth/LittleBigMouse · error · std::io::Error

NotFound

NotFound

Error message

no per-user runtime directory

What it means

default_endpoint() builds the IPC socket path by asking lbm_ipc::endpoint::socket_path to pick between XDG_RUNTIME_DIR and the fallback data directory. When neither yields a usable per-user path, it returns NotFound with "no per-user runtime directory". The IPC server cannot be started or located without a valid socket path.

Solutions

  1. Ensure XDG_RUNTIME_DIR is set, e.g. export XDG_RUNTIME_DIR=/run/user/$(id -u) before launching the daemon/service.
  2. In systemd units add Environment=XDG_RUNTIME_DIR=/run/user/%U (or use ExecStart with a user session slice so the variable is inherited).
  3. If relying on the fallback, make sure the lbm data directory exists and is writable by the current user.
  4. Pre-create the runtime directory with correct ownership: install -d -m 700 -o $USER /run/user/$(id -u).

Example fix

# before (fails in systemd unit)
ExecStart=/usr/bin/littlebigmouse
# after
ExecStart=/usr/bin/littlebigmouse
Environment=XDG_RUNTIME_DIR=/run/user/%U
Defensive patterns

Strategy: validation

Validate before calling

// before starting the IPC server
if std::env::var_os("XDG_RUNTIME_DIR").map(|v| v.is_empty()).unwrap_or(true) {
    std::env::set_var("XDG_RUNTIME_DIR", format!("/run/user/{}", nix::unistd::getuid()));
}

Try / catch

match default_endpoint() {
    Ok(ep) => listen(ep),
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        eprintln!("XDG_RUNTIME_DIR missing; set it to /run/user/$UID");
        std::process::exit(1);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling default_endpoint() when the XDG_RUNTIME_DIR environment variable is unset/empty AND the fallback lbm_data_file("") path is also unavailable (e.g. socket_path returned None), so there is no writable per-user directory to place the Unix domain socket.

Common situations: Running the daemon from a systemd unit or cron job with a minimal environment where XDG_RUNTIME_DIR is not exported; su/sudo dropping the env var; non-standard login shells; running as a system user with no XDG session and unwritable data dir.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of mgth/LittleBigMouse@7a42f01d47 (2026-09-16). Data as JSON: /api/errors/75f5ee814674c970. Report an issue: GitHub.

Appendix: source

Thrown at rust/crates/lbm-hook/src/ipc/server.rs:458

        pub async fn run(self, server: ServerHandle, _shared: &'static Shared) {
            let semaphore = Arc::new(Semaphore::new(MAX_CLIENTS));
            while let Ok((stream, _)) = self.listener.accept().await {
                let Ok(permit) = semaphore.clone().try_acquire_owned() else {
                    continue;
                };
                tokio::spawn(run_connection(stream, server.clone(), permit));
            }
            let _ = std::fs::remove_file(&self.path);
        }
    }

    pub fn default_endpoint() -> io::Result<String> {
        let runtime = std::env::var_os("XDG_RUNTIME_DIR").map(PathBuf::from);
        let data = crate::platform::paths::lbm_data_file("");
        lbm_ipc::endpoint::socket_path(runtime.as_deref(), data.as_deref())
            .map(|path| path.to_string_lossy().into_owned())
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "no per-user runtime directory"))
    }
}

View on GitHub (pinned to 7a42f01d47)