Skip to content

Plugin hot-reload while locked destroys the lock client; Quickshell then SIGABRTs #9441

Description

@oliverlukschander

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: recoveringlock-requestedlock-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 → qFatalabort()), 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

  1. Lock the session (idle timeout or omarchy system lock) and wait until the lock is secure.
  2. Save/touch a file in an enabled plugin under ~/.config/omarchy/plugins/ (or let a background agent do so).
  3. Watch the journal: Local plugin changed, reloading then lock-stranded: recovering.
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions