Repository navigation
WlSessionLock crashes when an active lock surface loses its output #1155
Description
Activity
Confirming this on a different setup: desktop, idle/wake (no suspend, no lid), single output, AMD GPU. Same log chain, same exit 255. Hyprland stayed up.
Environment
- Quickshell 0.3.1-1, Qt 6.11.2, Hyprland 0.56.2 (
efb5099), Aquamarine 0.15.0 - Omarchy 4.0.4 (stock
omarchy.lock/WlSessionLock) - GPU: AMD RX 6700 XT (
1002:73df) + Intel Haswell iGPU (8086:0412) - One output:
DP-1 - Idle: screensaver 150s, lock 300s. Lock blanks the panel 5s later via
omarchy-brightness-display off(DPMS), not a lid event.
What happened
- Idle lock succeeded (
secure=true) at 13:01. - User input at 13:23:49 (
idle-monitor: active). - Seven seconds later the last real output was gone. Qt made a placeholder screen, lock surfaces were skipped, Hyprland IPC saw an untracked
FALLBACKremoval, then the Wayland connection died (Invalid argument). Process exited 255. - Watchdog relaunched the shell; Omarchy's stranded-lock recovery retook the lock (
secure=true). - The same zero-output /
FALLBACK/ fatal-error / 255 sequence repeated ~40s later on the recovered instance. - After the second relaunch, PAM unlock worked. Session apps were intact (Hyprland never crashed). Hyprland's "lockscreen app died" failsafe was visible in the gap.
Log (trimmed; twice in one wake)
13:23:49 idle-monitor: active 13:23:56 qt.qpa.wayland: There are no outputs - creating placeholder screen 13:23:56 Layershell screen does not correspond to a real screen. 13:23:56 Not creating lock surface for screen QScreen(..., name="") as it is not backed by a valid wayland output. 13:23:56 quickshell.hyprland.ipc: Got removal for monitor "FALLBACK" which was not previously tracked. 13:23:56 The Wayland connection experienced a fatal error: Invalid argument 13:23:56 Omarchy shell exited with status 255; relaunching. 13:24:02 lock-stranded: recovering 13:24:03 secure=true … ~30s later, identical placeholder / empty QScreen / FALLBACK / Invalid argument / 255 … 13:24:39 lock-stranded: recovering 13:24:40 secure=trueAgrees with the report that the
FALLBACKline looks like a timing marker, not the request that kills the connection. Extra datapoint: this is not NVIDIA-specific and does not need suspend or a laptop lid — idle blank on a single output is enough, and it can fire twice on one wake while outputs are still settling.Reacted by Idris Gadi- Quickshell 0.3.1-1, Qt 6.11.2, Hyprland 0.56.2 (
Third confirmation, on hardware narrower than either report above: AMD Ryzen 7 6800U iGPU only — no discrete GPU, no Intel iGPU, one output (HDMI-A-1). Same chain, same exit 255. Omarchy 4.0.0 (
omarchy-dev 4.0.0.r2155.gf2cf3ce), Quickshell 0.3.1, kernel 7.2.5-4-omarchy. Trigger is plain idle-blank DPMS — no suspend, no lid, no external monitor, matching @dpan.I won't repeat the log chain, which matches @dpan's exactly. Four things I can add:
1. It is a race, not a certainty — about 23%
Over this journal's lifetime:
Event Count attempted to use dangling screen object4296 Got removal for monitor "FALLBACK"1770 The Wayland connection experienced a fatal error406 1770 zero-output events produced 406 fatal exits. Most zero-output transitions are survived; it seems to depend on whether lock-surface realization is in flight as the outputs tear down. That may explain why it fires twice on one wake for @dpan and not at all on other wakes.
2. It can loop for hours, not just twice
@dpan saw two iterations in one wake. My longest unbroken loop ran 2026-09-18 12:35:34 → 18:17:20 — 5h42m, roughly 395 crashes, at a steady 17–18s per iteration. The stranded-lock recovery re-locks, hits the same zero-output state, and exits again indefinitely. Omarchy's relaunch limiter (5 per 60s) never trips, because 17–18s is only ~3.5/minute.
3. The
_exit()path leaks file descriptors until unrelated apps breakBecause the process leaves through the fatal Wayland error rather than the crash reporter — which is why there's no
report.txt, as the original report notes — no destructors run, soProcesschildren are never reaped. Each iteration orphaned oneinotifywaittosystemd --user:$ ps -o ppid= -p $(pgrep -d, -f inotifywait) | sort | uniq -c | sort -rn 398 1116 (systemd --user) 1 3453442 (quickshell) <- the live one398 orphans against 406 crashes. Each holds an inotify instance, and
fs.inotify.max_user_instancesis 1024 per UID — I was at roughly 463. Past that ceiling every laterinotify_init1()in the session fails withEMFILE, surfacing in whatever application next asks for a watch, with nothing pointing back at the shell.So the blast radius is wider than a shell restart: a long enough loop degrades the whole user session. (Downstream, omacom/omarchy#11385 adds
setpriv --pdeathsig TERMto contain the leak on the Omarchy side, but the fd exhaustion is a consequence of the_exit()path here.)4. Does
afb2c27calready cover this?afb2c27c("wayland/lock: guard against reentrancy during surface creation", 2026-08-25, five days after the v0.3.1 tag) looks directly relevant, and is unreleased:onScreensChanged()gains a!this->realizingguard, with the comment "Theoretically screens shouldnt be invalidated while realizing, instead in later event loop cycles." On this hardware they demonstrably are.- A failed
manager->lock()now callsunlock()and returns, instead of falling through toupdateSurfaces(true, old)as 0.3.1 does.
Is this case expected to be fixed by that commit? If so, a release would help — every reporter here is on 0.3.1 from their distro. I'm happy to build master and run the reproducer against it if that's useful; at a ~23% per-transition rate it should take only a few idle cycles to get a signal either way.
Another trigger for the same chain: laptop with three external displays on a USB-C dock, suspended while locked, dock unplugged during suspend. No DPMS or idle involved. On resume every output the lock surfaces were on is gone at once.
Quickshell 0.3.1-1, Qt 6.11.2, Hyprland 0.56.2 (
efb5099), Omarchy 4.0.4, Framework 13 (Ryzen 7040, 780M iGPU only), kernel 7.2.5.hyprmoncfgdswitches to the internal-only profile on resume.One detail I haven't seen in the other reports: the internal panel was back for almost 6 s before the fatal error, and the lock never got a surface on it.
16:45:22.26 kernel resume complete 16:45:23.43 hyprland: monitorremoved DP-9, DP-10, DP-12 (the 3 dock outputs) 16:45:23.57 hyprland: monitoradded FALLBACK 16:45:23.62 qt.qpa.wayland: There are no outputs - creating placeholder screen 16:45:24.94 Not creating lock surface for screen QScreen(0x…df40, name="") as it is not backed by a valid wayland output. (x3) 16:45:25.98 hyprmoncfgd: applied profile (eDP-1 enabled) 16:45:26.00 hyprland: monitoradded eDP-1 16:45:26.03 hyprland: monitorremoved FALLBACK 16:45:26.15 Not creating lock surface for screen QScreen(0x…df40, name="") … 16:45:27.79 Not creating lock surface for screen QScreen(0x…7430, name="") … (x3, different QScreen) 16:45:29.91 Not creating lock surface for screen QScreen(0x…7430, name="") … 16:45:31.69 attempted to use dangling screen object (x12) 16:45:31.70 quickshell.hyprland.ipc: Got removal for monitor "FALLBACK" which was not previously tracked. 16:45:32.10 hyprland: error in client communication (pid …) 16:45:32.30 The Wayland connection experienced a fatal error: Invalid argument 16:45:32.37 exited with status 255; relaunching 16:45:34.24 lock-stranded: recovering (new instance locks fine on eDP-1)So:
eDP-1was added at 26.00, but every later "not creating lock surface" line still refers to a namelessQScreen. A second namelessQScreen(0x…7430) shows up at 27.79 and the lock skips it the same way.WlSessionLockdoesn't seem to retry once a usable screen shows up.- The Hyprland IPC removal of
FALLBACK(sent by the compositor at 26.03) only reaches Quickshell at 31.70, about 5.7 s late. During that window the shell rebuilt its per-screen panels three times. That fits the "timing marker" reading: the dangling-screen accesses and the fatal request come out of the same backlog being processed.
In my journal (60 days) this happened only once: 8
FALLBACKremovals, 13 dangling-screen warnings, 1 fatal error. The resume above is the only one where every output disappeared while locked. It left one orphanedinotifywaitundersystemd --user, matching @calebl's point 3.Locking, suspending and pulling the dock seems to be a fairly deterministic way to get a zero-output state while the lock is active, in case that helps check
afb2c27c.
When the last real Wayland output temporarily disappears while the session is locked, Quickshell exits with status 255. This occurs during suspend/resume, DPMS transitions, or external-monitor disconnection.
Hyprland remains running and the session remains locked, but the shell must be restarted.
Reproduction
Observed behavior
QtWayland creates a placeholder screen after the last output disappears. Quickshell rejects the placeholder screen, then the Wayland connection terminates:
QScreen(...)as it is not backed by a valid wayland output.Quickshell exits with status 255. The FALLBACK warning appears to be a timing marker rather than the source of the fatal Wayland request.
Expected behavior
Quickshell should remain locked and running through a temporary zero-output state, then restore its lock surface when an output returns.
Environment
Quickshell: 0.3.1-1
Qt: 6.11.2
Hyprland: 0.56.2
Aquamarine: 0.15.0
NVIDIA: 610.57.04
GPU setup: NVIDIA GPU with AMD iGPU
No
report.txtwas generated because the process exited through the fatal Wayland connection error rather than Quickshell's crash reporter.