niri-wm/niri · error · io::Error

io::ErrorKind::NotFound

io::ErrorKind::NotFound

Error message

NIRI_SOCKET is not set, are you running this within niri?

What it means

niri-ipc's Socket::connect() reads the socket path from the NIRI_SOCKET environment variable — niri exports it to every process it spawns (terminals, app launchers). The variable is unset, so connect() fails fast with ErrorKind::NotFound before any socket is opened: the caller is not running as a descendant of a niri session. The message is a hint ('are you running this within niri?'), not a permission or socket problem.

Source

Thrown at niri-ipc/src/socket.rs:29

/// Name of the environment variable containing the niri IPC socket path.
pub const SOCKET_PATH_ENV: &str = "NIRI_SOCKET";

/// Helper for blocking communication over the niri socket.
///
/// This struct is used to communicate with the niri IPC server. It handles the socket connection
/// and serialization/deserialization of messages.
pub struct Socket {
    stream: BufReader<UnixStream>,
}

impl Socket {
    /// Connects to the default niri IPC socket.
    ///
    /// This is equivalent to calling [`Self::connect_to`] with the path taken from the
    /// [`SOCKET_PATH_ENV`] environment variable.
    pub fn connect() -> io::Result<Self> {
        let socket_path = env::var_os(SOCKET_PATH_ENV).ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::NotFound,
                format!("{SOCKET_PATH_ENV} is not set, are you running this within niri?"),
            )
        })?;
        Self::connect_to(socket_path)
    }

    /// Connects to the niri IPC socket at the given path.
    pub fn connect_to(path: impl AsRef<Path>) -> io::Result<Self> {
        let stream = UnixStream::connect(path.as_ref())?;
        let stream = BufReader::new(stream);
        Ok(Self { stream })
    }

    /// Sends a request to niri and returns the response.
    ///
    /// Return values:
    ///

View on GitHub (pinned to 606284464d)

Solutions

  1. Run the command from a terminal launched inside niri (it inherits NIRI_SOCKET); that is the supported path.
  2. Set the variable manually for out-of-session contexts: NIRI_SOCKET=$XDG_RUNTIME_DIR/niri.wayland-1 niri msg ... (check the actual path with 'ls $XDG_RUNTIME_DIR | grep niri' from inside the session).
  3. For systemd user units, import the variable: add 'PassEnvironment=NIRI_SOCKET' style plumbing or read the path in an EnvironmentFile written at login.
  4. If the goal is automation from outside, connect_to(path) directly with the discovered socket path instead of connect().

Example fix

# before: no inherited session environment
ssh host 'niri msg action focus-column-right'
# error: NIRI_SOCKET is not set, are you running this within niri?

# after: point the client at the session socket explicitly
ssh host 'NIRI_SOCKET=/run/user/1000/niri.wayland-1 niri msg action focus-column-right'
Defensive patterns

Strategy: validation

Validate before calling

// Rust (niri-ipc): check the env var and a fallback path before connecting
let path = std::env::var_os("NIRI_SOCKET")
    .or_else(|| {
        let p = std::env::temp_dir().join(format!("niri.{}.wayland-1", uid));
        p.exists().then_some(p.into_os_string())
    })
    .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "not running inside niri"))?;
let socket = Socket::connect_to(path)?;

Type guard

fn is_running_under_niri() -> bool {
    std::env::var_os("NIRI_SOCKET").is_some()
}

Try / catch

match Socket::connect() {
    Ok(s) => s,
    Err(e) if e.kind() == io::ErrorKind::NotFound => {
        // not an IPC failure: we are outside the niri session
        eprintln!("NIRI_SOCKET is not set; run this inside niri or connect_to() the socket in $XDG_RUNTIME_DIR");
        std::process::exit(2);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Running 'niri msg ...' (or any niri-ipc client calling Socket::connect()) from a context that did not inherit niri's environment: SSH login, systemd user service unit, cron, another compositor, or a shell started before niri.

Common situations: Remoting in via SSH and trying to control the local niri; scripts wired to systemd user timers/services or udev rules where NIRI_SOCKET is not in the environment; launching niri msg from a new login after niri was started elsewhere; using niri-ipc in a test harness outside the session.

Related errors


AI-assisted analysis of niri-wm/niri@606284464d (2026-08-16). Data as JSON: /api/errors/2b6dd16dcb6c7789. Report an issue: GitHub.