niri --session hangs at startup without a D-Bus session bus (main thread waits on env-import child, which waits on niri's X11 socket)
Summary
Starting niri --session from a TTY when no session bus exists (DBUS_SESSION_BUS_ADDRESS unset, no $XDG_RUNTIME_DIR/bus) leaves niri hanging indefinitely. Screen on this tty stays frozen and keyboard input is unresponsive because niri holds the keyboard; SysRq+R (unraw) is the only way I found to get the keyboard back.
Killing the child dbus-launch from another VT immediately unblocks niri, and startup then continues normally (without a session bus).
The process tree shows a wait cycle:
- niri's main thread blocks in
wait4()on a childsh(the environment import). - That child runs
dbus-update-activation-environment, which autolaunchesdbus-launch. dbus-launchhasDISPLAY=:2(the X11 display niri reported in its log) in its environment. One connection sits in the accept queue of niri's abstract X11 socket, and niri never accepts it because its main thread is blocked.
Environment
- Distro: Void Linux (runit, no systemd), elogind
- niri 26.04, installed from the Void repositories (the log shows
unknown commit) - xwayland-satellite 0.8.3, dbus 1.16.2
- Started from tty2 with
niri --session(niri-sessionis the systemd wrapper, so on non-systemd systemsniri --sessionis the way to start it), withoutdbus-run-session DBUS_SESSION_BUS_ADDRESSis unset,/run/user/1000/busdoes not exist
Steps to reproduce
- On a system with no session bus for this login, log in on a TTY.
- Run
RUST_LOG=niri=debug niri --session > ~/niri.log 2>&1. - The TTY stays exactly as it was before launching niri, and the keyboard is unusable. The niri log stops right after
listening on X11 socket: :2. - From another VT,
kill <pid of dbus-launch>. niri immediately continues startup: the import shell exits with status 71 and niri logs warnings about the missing session bus.
Observations (details below)
- The log has no output between
listening on X11 socket: :2(19:07:28) and the first line after the kill (19:52:00), i.e. the hang lasted until I killeddbus-launch. pstree:niri → sh → dbus-update-activation-environment → dbus-launch.strace -pon each process:- niri (2031):
wait4(2036 sh(2036):wait4(-1dbus-update-activation-environment(2037):read(3dbus-launch(2038):restart_syscall
- niri (2031):
dbus-launchhasDISPLAY=:2and noDBUS_*variables in its environment.ss -xplduring the hang: the abstract socket@/tmp/.X11-unix/X2owned by niri hasRecv-Q 1, i.e. one connection waiting foraccept().- About 20 ms after the kill, niri logs
connection to X11 abstract socket; spawning xwayland-satellite, which is what you would expect if a connection had been queued on that socket the whole time. I haven't captured theconnect()call itself, so I can't prove it came fromdbus-launch, but nothing else I started hadDISPLAY=:2. - niri already handles a failed import gracefully (
import environment shell exited with exit status: 71is only a warning). The problem is only that it waits for the child synchronously and without a timeout. - The
error starting org.gnome.*/ScreenSaver/locale1warnings after recovery are just the result of there being no session bus. The DRMPermission deniedandpausing/resuming sessionlines at the end most likely come from my VT switches (I rankillfrom another VT).
Expected behavior
niri should not block its event loop waiting for a child process that may depend on niri itself (here, indirectly through the X11 socket). Possible approaches: run the environment import asynchronously, add a timeout, or skip the D-Bus import when no session bus is available. I'll leave the choice to you.
Workaround
dbus-run-session niri --session (the autolaunch is not triggered).
niri.log (full, including the lines after recovery)
2026-10-22T19:07:28.558581Z INFO niri: starting version 26.04 (unknown commit)
2026-10-22T19:07:28.596922Z DEBUG niri_config: loaded config from "/home/oleksa/.config/niri/config.kdl"
2026-10-22T19:07:28.727249Z INFO niri::backend::tty: using as the render node: "/dev/dri/renderD128"
2026-10-22T19:07:28.763887Z DEBUG niri::backend::tty: adding device: 57856 "/dev/dri/card0"
2026-10-22T19:07:28.763924Z DEBUG niri::backend::tty: this is the primary node
2026-10-22T19:07:28.813378Z DEBUG niri::backend::tty: got render node: renderD128
2026-10-22T19:07:28.813396Z DEBUG niri::backend::tty: initializing the primary renderer
2026-10-22T19:07:28.861376Z DEBUG niri::backend::tty: device changed: 57856
2026-10-22T19:07:28.874226Z DEBUG niri::backend::tty: new connector: eDP-1 "Chimei Innolux Corporation 0x1481 Unknown"
2026-10-22T19:07:28.874382Z DEBUG niri::backend::tty: connecting connector: eDP-1
2026-10-22T19:07:28.874398Z DEBUG niri::backend::tty: picking mode: Mode { name: "1600x900", clock: 140190, size: (1600, 900), hsync: (1806, 1943, 2286), vsync: (911, 926, 1022), hskew: 0, vscan: 0, vrefresh: 60, mode_type: ModeTypeFlags(PREFERRED | DRIVER) }
2026-10-22T19:07:28.874433Z DEBUG niri::backend::tty: couldn't reset HDR properties: couldn't find property: "HDR_OUTPUT_METADATA"
2026-10-22T19:07:28.882422Z DEBUG niri::niri: putting output eDP-1 at x=0 y=0
2026-10-22T19:07:28.882489Z INFO niri: listening on Wayland socket: wayland-1
2026-10-22T19:07:28.882495Z INFO niri: IPC listening on: /run/user/1000/niri.wayland-1.2031.sock
2026-10-22T19:07:28.884485Z INFO niri: listening on X11 socket: :2
dbus-update-activation-environment: error: unable to connect to D-Bus: /usr/bin/dbus-launch terminated abnormally without any error message
2026-10-22T19:52:00.263922Z WARN niri: import environment shell exited with exit status: 71
2026-10-22T19:52:00.280074Z WARN niri::dbus: error starting org.gnome.Mutter.ServiceChannel: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.280181Z WARN niri::dbus: error starting org.gnome.Mutter.DisplayConfig: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.280281Z WARN niri::dbus: error starting org.freedesktop.ScreenSaver: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.280370Z WARN niri::dbus: error starting org.gnome.Shell.Screenshot: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.280719Z WARN niri::dbus: error starting org.gnome.Shell.Introspect: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.280787Z WARN niri::dbus: error starting org.gnome.Mutter.ScreenCast: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.280835Z WARN niri::dbus: error starting org.freedesktop.a11y.KeyboardMonitor: I/O error: No such file or directory (os error 2)
2026-10-22T19:52:00.284633Z DEBUG niri::utils::xwayland::satellite: connection to X11 abstract socket; spawning xwayland-satellite
2026-10-22T19:52:00.287520Z WARN niri::dbus::freedesktop_locale1: error receiving initial properties: ServiceUnknown("The name org.freedesktop.locale1 was not provided by any .service files")
2026-10-22T19:52:00.383238Z WARN niri::cursor: error loading xcursor default@24: no default icon
2026-10-22T19:52:00.404362Z WARN niri::backend::tty: error queueing frame: The underlying drm surface encountered an error: DRM access error: Page flip commit failed on device `Some("/dev/dri/card0")` (Permission denied (os error 13))
2026-10-22T19:52:00.404484Z DEBUG niri::backend::tty: pausing session
2026-10-22T19:52:02.100951Z DEBUG niri::backend::tty: resuming session
2026-10-22T19:52:02.283264Z DEBUG niri::backend::tty: device changed: 57856
2026-10-22T19:52:02.310442Z DEBUG niri::backend::tty: couldn't reset HDR properties: couldn't find property: "HDR_OUTPUT_METADATA"
2026-10-22T19:52:07.443690Z DEBUG niri::backend::tty: pausing session(The Caused by: No such file or directory (os error 2) continuation lines after each D-Bus warning are omitted for brevity.)
pstree and strace (during the hang)
$ pstree -p 2031
niri(2031)─┬─sh(2036)───dbus-update-act(2037)───dbus-launch(2038)
├─{niri}(2032)
├─{niri}(2033)
└─{niri}(2034)
$ sudo strace -p 2031
wait4(2036
$ sudo strace -p 2036
wait4(-1
$ sudo strace -p 2037
read(3
$ sudo strace -p 2038
restart_syscall(<... resuming interrupted restart_syscall ...>Sockets, environment and fds of dbus-launch (during the hang)
$ ss -xp | grep -E 'dbus-launch|niri' && ss -xpl | grep -E 'dbus-launch|niri'
u_str ESTAB 0 768 * 14424 * 0 users:(("dbus-launch",pid=2038,fd=3))
u_str ESTAB 2034 0 * 15384 * 13415 users:(("niri",pid=2031,fd=12))
u_str LISTEN 0 4096 /tmp/.X11-unix/X2 13427 * 0 users:(("niri",pid=2031,fd=44),("niri",pid=2031,fd=41))
u_str LISTEN 0 4096 /run/user/1000/wayland-1 12619 * 0 users:(("niri",pid=2031,fd=28))
u_str LISTEN 0 4096 /run/user/1000/niri.wayland-1.2031.sock 12620 * 0 users:(("niri",pid=2031,fd=29))
u_str LISTEN 1 4096 @/tmp/.X11-unix/X2 13426 * 0 users:(("niri",pid=2031,fd=43),("niri",pid=2031,fd=40))
$ tr '\0' '\n' < /proc/2038/environ | grep -E '^(DISPLAY|DBUS|XDG_RUNTIME)'
XDG_RUNTIME_DIR=/run/user/1000
DISPLAY=:2
$ ls -l /proc/2038/fd
0 -> /dev/null
1 -> pipe:[13430]
2 -> pipe:[13431]
3 -> socket:[14424]Activity
4I know that dbus-run-session niri --session works. But deadlock after incorrect start is a problem anyway.
I think this is a "patches welcome" situation since it's a weird setup. But the patch must work and not be ugly.
Though honestly I'm leaning towards a "works as intended" here because the --session flag says "Import environment globally to systemd and D-Bus, run D-Bus services", so if you're running this flag without a session bus then clearly you're doing something wrong.
run the environment import asynchronously
This is wrong, the environment must be imported before signaling the niri service start, otherwise services won't get $WAYLAND_DISPLAY.
skip the D-Bus import when no session bus is available
Maybe this, if there's a clean (and fast) way to check, while also logging a warning if it goes wrong.
I dug into why this happens and I can reproduce it without niri.
Cause. In src/main.rs, xwayland::satellite::setup() makes niri listen on its own X11 sockets, and niri then sets DISPLAY to point at them. Right after that, import_environment() spawns /bin/sh -c 'dbus-update-activation-environment ...' and blocks in child.wait(). This happens before event_loop.run(), so niri does not accept connections on its X11 socket while it waits.
The child inherits DISPLAY. When no session bus exists, libdbus autolaunches dbus-launch, which uses DISPLAY to connect to an X11 server. It connects to niri's socket, never gets a reply, and never exits. So niri waits for the child, and the child waits for niri.
Reproduction without niri (from a TTY, DBUS_SESSION_BUS_ADDRESS unset):
- In one terminal, create an abstract socket that listens but never accepts connections:
python3 -c "
import socket, time
s = socket.socket(socket.AF_UNIX)
s.bind('\0/tmp/.X11-unix/X9')
s.listen(1)
time.sleep(600)
"- In another terminal:
env -u DBUS_SESSION_BUS_ADDRESS DISPLAY=:9 timeout 10 dbus-update-activation-environment WAYLAND_DISPLAY; echo $?It hangs until timeout kills it (exit code 124). With DISPLAY unset instead, it fails immediately with an error that DISPLAY is not set. In my original report, killing the hung dbus-launch was enough to let niri continue.
I know that starting niri through dbus-run-session avoids this. The problem is that a missing session bus ends in an unbounded hang with the keyboard grabbed. niri already handles a failed import gracefully (it just logs a warning, e.g. exit status: 71, and keeps starting), but it cannot handle an import that never finishes.
Use
dbus-run-session niri --session