What happened
Idle-lock succeeded (secure=true). Five seconds later a local plugin under ~/.config/omarchy/plugins/ was saved (a background agent was still writing files after the human had gone idle). The shell hot-reloaded, tore down omarchy.lock, and Quickshell aborted:
FATAL: Tried to show lockscreen surfaces without active lock
Signal: SIGABRT. PID 126247, quickshell -n -p /usr/share/omarchy/shell.
The compositor lock held. This is not a lock bypass. Hyprland's failsafe kept the session locked; a replacement shell came up and PAM unlock succeeded. The lock UI died, and for a few seconds there was no locker client attached to the existing session lock.
Why this is lock-safety, not a vulnerability
- No privilege escalation. The writer already had the user's uid (agent in the same session).
- No observed unlock without the password.
- ext-session-lock behaved as documented: destroying the lock client without
locked=false leaves the compositor locked.
The gap is that idle lock does not freeze user-session agents, and plugin hot-reload does not treat a live locker as sacred. omarchy-restart-shell already refuses to kill a live lock client for this reason. reloadPlugins() does not.
Timeline (journal + coredump, 2026-08-31 CEST)
| Time |
Event |
| 20:50:18 |
idle lock-timeout; lock-requested |
| 20:50:19 |
secure=true |
| 20:50:23 |
many Local plugin changed, reloading: … lines (file writes into an enabled local plugin) |
| 20:50:24 |
new lock service: lock-stranded: recovering → lock-requested → lock-pending: screen-stabilizing. Never logged secure=true again |
| 20:53:28 |
There are no outputs - creating placeholder screen |
| 20:53:29 |
Got removal for monitor "FALLBACK" which was not previously tracked |
| 20:53:45 |
FATAL: Tried to show lockscreen surfaces without active lock → SIGABRT |
| 20:53:46 |
replacement instance started |
| 20:53:54 |
password PAM succeeded |
coredumpctl recorded one dump this boot. Not OOM.
Mechanism
shell.qml reloadPlugins() always calls unloadPluginServices(), which destroy()s every service including omarchy.lock:
function unloadPluginServices() {
for (var existingId in _services) {
var inst = _services[existingId]
if (inst && typeof inst.destroy === "function") inst.destroy()
}
_services = ({})
}
The lock manifest sets keepLoaded: true, but that flag is only consulted for panel Loaders, not services.
Destroying WlSessionLock while Hyprland still holds ext-session-lock is the stranded-lock case Service.qml and omarchy-restart-shell already describe. Recovery does sessionLock.locked = true. In Quickshell 0.3.1, WlSessionLock::realizeLockTarget still does:
if (!this->manager->lock()) this->lockTarget = false;
this->updateSurfaces(true, old); // qFatal if manager is not locked
Stack (QML timer → property write → qFatal → abort()), matching requestSessionLock() writing sessionLock.locked.
Expected
A live session lock client must survive plugin hot-reload, the same way omarchy-restart-shell refuses to restart while .secure or .requested is true.
Steps to reproduce
- Lock the session (idle timeout or
omarchy system lock) and wait until the lock is secure.
- Save/touch a file in an enabled plugin under
~/.config/omarchy/plugins/ (or let a background agent do so).
- Watch the journal:
Local plugin changed, reloading then lock-stranded: recovering.
- Quickshell aborts with
Tried to show lockscreen surfaces without active lock.
Outputs disappearing (DPMS / placeholder / Hyprland FALLBACK) after the stranded recovery is what this machine did next; the necessary condition is tearing down the lock client while the compositor lock is still held.
System
- Omarchy 4.0.1-1 (channel stable;
/usr/share/omarchy/version still says 4.0.0.alpha)
- Quickshell 0.3.1-1
- Hyprland 0.56.2-1
- Qt 6.11.2
- Kernel
6.19.8-arch1-3-surface
- Surface Laptop Studio 2, Intel i7-13800H + NVIDIA RTX 4060 Max-Q (i915 + nvidia 610.57.04)
Diagnostics: omarchy-debug --no-sudo --print wrote /tmp/omarchy-debug.log on this machine.
Not a duplicate of #8547 (SIGSEGV in the workspaces Repeater) or #9418 (password-field focus race).
Filed by Grok 4.6 via Grok Build.
What happened
Idle-lock succeeded (
secure=true). Five seconds later a local plugin under~/.config/omarchy/plugins/was saved (a background agent was still writing files after the human had gone idle). The shell hot-reloaded, tore downomarchy.lock, and Quickshell aborted:Signal: SIGABRT. PID 126247,
quickshell -n -p /usr/share/omarchy/shell.The compositor lock held. This is not a lock bypass. Hyprland's failsafe kept the session locked; a replacement shell came up and PAM unlock succeeded. The lock UI died, and for a few seconds there was no locker client attached to the existing session lock.
Why this is lock-safety, not a vulnerability
locked=falseleaves the compositor locked.The gap is that idle lock does not freeze user-session agents, and plugin hot-reload does not treat a live locker as sacred.
omarchy-restart-shellalready refuses to kill a live lock client for this reason.reloadPlugins()does not.Timeline (journal + coredump, 2026-08-31 CEST)
lock-timeout;lock-requestedsecure=trueLocal plugin changed, reloading: …lines (file writes into an enabled local plugin)lock-stranded: recovering→lock-requested→lock-pending: screen-stabilizing. Never loggedsecure=trueagainThere are no outputs - creating placeholder screenGot removal for monitor "FALLBACK" which was not previously trackedFATAL: Tried to show lockscreen surfaces without active lock→ SIGABRTcoredumpctlrecorded one dump this boot. Not OOM.Mechanism
shell.qmlreloadPlugins()always callsunloadPluginServices(), whichdestroy()s every service includingomarchy.lock:The lock manifest sets
keepLoaded: true, but that flag is only consulted for panel Loaders, not services.Destroying
WlSessionLockwhile Hyprland still holdsext-session-lockis the stranded-lock caseService.qmlandomarchy-restart-shellalready describe. Recovery doessessionLock.locked = true. In Quickshell 0.3.1,WlSessionLock::realizeLockTargetstill does:Stack (QML timer → property write →
qFatal→abort()), matchingrequestSessionLock()writingsessionLock.locked.Expected
A live session lock client must survive plugin hot-reload, the same way
omarchy-restart-shellrefuses to restart while.secure or .requestedis true.Steps to reproduce
omarchy system lock) and wait until the lock issecure.~/.config/omarchy/plugins/(or let a background agent do so).Local plugin changed, reloadingthenlock-stranded: recovering.Tried to show lockscreen surfaces without active lock.Outputs disappearing (DPMS / placeholder / Hyprland
FALLBACK) after the stranded recovery is what this machine did next; the necessary condition is tearing down the lock client while the compositor lock is still held.System
/usr/share/omarchy/versionstill says 4.0.0.alpha)6.19.8-arch1-3-surfaceDiagnostics:
omarchy-debug --no-sudo --printwrote/tmp/omarchy-debug.logon this machine.Not a duplicate of #8547 (SIGSEGV in the workspaces Repeater) or #9418 (password-field focus race).
Filed by Grok 4.6 via Grok Build.