niri-wm/niri · error · anyhow::Error
failed to register any org.freedesktop.ScreenSaver interface
Error message
failed to register any org.freedesktop.ScreenSaver interface
What it means
niri's idle-inhibit D-Bus server exports its ScreenSaver implementation at both /org/freedesktop/ScreenSaver and /ScreenSaver on the session bus; zbus's object_server().at() returns Ok(false) when an interface with that name is already registered at the path. If BOTH paths are taken, niri bails with this message — some other process in the session is already serving org.freedesktop.ScreenSaver, so registering would silently shadow it.
Source
Thrown at src/dbus/freedesktop_screensaver.rs:149
impl Start for ScreenSaver {
fn start(self) -> anyhow::Result<zbus::blocking::Connection> {
let is_inhibited = self.is_inhibited.clone();
let is_broken = self.is_broken.clone();
let inhibitors = self.inhibitors.clone();
let monitor_task = self.monitor_task.clone();
let conn = zbus::blocking::Connection::session()?;
let flags = RequestNameFlags::AllowReplacement
| RequestNameFlags::ReplaceExisting
| RequestNameFlags::DoNotQueue;
let org_fd_ss_registered = conn
.object_server()
.at("/org/freedesktop/ScreenSaver", self.clone())?;
let ss_registered = conn.object_server().at("/ScreenSaver", self)?;
if !org_fd_ss_registered && !ss_registered {
anyhow::bail!("failed to register any org.freedesktop.ScreenSaver interface")
}
conn.request_name_with_flags("org.freedesktop.ScreenSaver", flags)?;
let async_conn = conn.inner();
let future = {
let conn = async_conn.clone();
async move {
if let Err(err) =
monitor_disappeared_clients(&conn, is_inhibited.clone(), inhibitors.clone())
.await
{
warn!("error monitoring org.freedesktop.ScreenSaver clients: {err:?}");
is_broken.store(true, Ordering::SeqCst);
is_inhibited.store(false, Ordering::SeqCst);
inhibitors.lock().unwrap().clear();
}
}View on GitHub (pinned to 606284464d)
Solutions
- Find the current owner: 'busctl --user tree | grep -i screensaver' or 'gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.ListNames', then stop that conflicting service.
- Kill leftover instances: 'pgrep -a niri' should show exactly one; 'pkill niri' and also check for stale Xwayland/portal processes.
- If nested inside another DE, reset the session bus context: 'systemctl --user stop gnome-session.target xdg-desktop-portal*' or run niri under its own bus (dbus-run-session niri).
- If two compositors must coexist, give the second one a private bus so the name/object paths do not collide.
Example fix
# before: conflicting owner on the session bus -> "failed to register any org.freedesktop.ScreenSaver interface" niri & # after: clean up the previous owner first busctl --user tree | grep -i screensaver # identify it systemctl --user stop xdg-desktop-portal.service pkill -x niri niri
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust (zbus): check for an existing owner before exporting your interfaces
let dbus = zbus::blocking::fdo::DBusProxy::new(&conn)?;
let has_owner = dbus.name_has_owner("org.freedesktop.ScreenSaver".into())?;
if has_owner {
warn!("another ScreenSaver provider is active; skipping registration");
} Try / catch
let a = conn.object_server().at("/org/freedesktop/ScreenSaver", iface.clone()).is_ok();
let b = conn.object_server().at("/ScreenSaver", iface).is_ok();
if !a && !b {
// degraded mode: feature unavailable, not fatal — log and continue serving everything else
warn!("failed to register any org.freedesktop.ScreenSaver interface");
} Prevention
- One session bus, one ScreenSaver provider: stop the previous compositor before starting a new one.
- When nesting or testing, isolate with 'dbus-run-session' so object paths cannot collide.
- At startup, probe org.freedesktop.DBus.NameHasOwner before exporting to fail soft instead of hard.
- Keep systemd user units from previous DEs from lingering: 'systemctl --user stop' xdg-desktop-portal* and session targets.
When it happens
Trigger: Running niri while another screen-saver provider owns those object paths: a leftover/nested niri instance, xdg-desktop-portal or a portal frontend, or a desktop session manager (e.g. GNOME components started via systemd user units) that also implements org.freedesktop.ScreenSaver on the same session bus.
Common situations: Starting niri from within an existing desktop session (GNOME/KDE services still running); a stale niri process after a crash-logout-login cycle; running two compositors side by side for testing on the same DBUS_SESSION_BUS_ADDRESS; systemd user services from a previous DE still active.
AI-assisted analysis of niri-wm/niri@606284464d (2026-08-16).
Data as JSON: /api/errors/72da297d6f6d5c31.
Report an issue: GitHub.