Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.
[stable 4.0.4] Interrupted update leaves root-owned inhibitor blocking suspend
Reported by argrig666 · filed Oct 4, 2026 · open at source
At a glance
- 1 · What is claimed?
- Only the report text below — no validator has restated it as checkable claims yet.
- 2 · What does it affect?
- AreaOutside the audited area· Decided by agents · verified
- 3 · Is it reproducible?
- No validation has been run yet.
- 4 · What remains unclear?
- Not validated yet: no claims, no reproducer.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
System details
- Omarchy: 4.0.4-1 (stable)
- Kernel: 7.2.5-3-omarchy
- systemd: 261 (261.2-1-arch)
- Architecture: x86_64
What's wrong?
An interrupted omarchy update can leave its privileged systemd-inhibit process running indefinitely. The inhibitor blocks both sleep and idle, so the system-menu Suspend action (systemctl suspend) silently fails even though no update or package operation remains active.
The leftover inhibitor was visible with systemd-inhibit --list:
WHO WHAT WHY MODE
omarchy-update sleep:idle Omarchy update in progress blockThe updater itself was gone, but this process chain had survived for about eight hours:
sudo systemd-inhibit --what=sleep:idle --who=omarchy-update \
--why="Omarchy update in progress" --mode=block sleep infinity
└─ sudo systemd-inhibit ...
└─ systemd-inhibit ...
└─ sleep infinityThe state file recorded the first sudo wrapper PID:
$ cat "$XDG_RUNTIME_DIR/omarchy-update-stay-awake/inhibit-pid"
139215 295390That PID was root-owned. omarchy-update-stay-awake stop runs as the desktop user and executes:
kill "$inhibit_pid" >/dev/null 2>&1 || trueThe signal therefore fails with EPERM. The subsequent start-time check sees the process still alive and reports:
Failed to stop the Omarchy update sleep inhibitor.Because start() begins by calling stop, later update attempts do not recover the stale inhibitor either.
Steps to reproduce
- Start
omarchy updateand let it reachomarchy-update-stay-awake start. - Interrupt or kill the updater before its normal cleanup completes.
- Confirm there is no remaining
omarchy-update,pacman,yay, orparuoperation. - Run
systemd-inhibit --list; the root-ownedomarchy-updateblocker remains. - Run
omarchy update stay awake stopas the desktop user; it cannot kill the recorded root-owned PID. - Select Suspend from the system menu or run
systemctl suspend; logind refuses the operation because the block inhibitor remains.
Expected behavior
Update cleanup should reliably terminate its own privileged sleep inhibitor. A later start or stop invocation should also recover a stale inhibitor after an interrupted update.
Actual behavior
The root-owned inhibitor survives after the update is gone and blocks suspend indefinitely, until the process is terminated with privilege or the machine is rebooted.
Likely cause
omarchy-update-stay-awake start launches sudo systemd-inhibit ... & and stores $!. That PID belongs to the privileged sudo process by the time cleanup runs. stop later attempts an ordinary unprivileged kill, suppresses its failure, and cannot release the inhibitor.
This appears hardware-independent. The symptom initially looked like a Dell/NVIDIA suspend problem, but the journal showed no new suspend attempt; after terminating only the stale inhibitor, suspend was unblocked.
Possible direction
Keep an unprivileged supervisor PID that can be signaled by the user and have it own/reap the privileged child, or make stop use the update's established privileged-command boundary to terminate the validated PID. The existing PID start-time check should remain to avoid PID-reuse mistakes.
Related but distinct: #8077 concerns children inheriting the update lock fd. This report concerns the update-owned sleep inhibitor itself surviving cleanup and blocking suspend.
View raw text
### System details
- Omarchy: 4.0.4-1 (stable)
- Kernel: 7.2.5-3-omarchy
- systemd: 261 (261.2-1-arch)
- Architecture: x86_64
### What's wrong?
An interrupted `omarchy update` can leave its privileged `systemd-inhibit` process running indefinitely. The inhibitor blocks both `sleep` and `idle`, so the system-menu Suspend action (`systemctl suspend`) silently fails even though no update or package operation remains active.
The leftover inhibitor was visible with `systemd-inhibit --list`:
```text
WHO WHAT WHY MODE
omarchy-update sleep:idle Omarchy update in progress block
```
The updater itself was gone, but this process chain had survived for about eight hours:
```text
sudo systemd-inhibit --what=sleep:idle --who=omarchy-update \
--why="Omarchy update in progress" --mode=block sleep infinity
└─ sudo systemd-inhibit ...
└─ systemd-inhibit ...
└─ sleep infinity
```
The state file recorded the first `sudo` wrapper PID:
```text
$ cat "$XDG_RUNTIME_DIR/omarchy-update-stay-awake/inhibit-pid"
139215 295390
```
That PID was root-owned. `omarchy-update-stay-awake stop` runs as the desktop user and executes:
```bash
kill "$inhibit_pid" >/dev/null 2>&1 || true
```
The signal therefore fails with `EPERM`. The subsequent start-time check sees the process still alive and reports:
```text
Failed to stop the Omarchy update sleep inhibitor.
```
Because `start()` begins by calling `stop`, later update attempts do not recover the stale inhibitor either.
### Steps to reproduce
1. Start `omarchy update` and let it reach `omarchy-update-stay-awake start`.
2. Interrupt or kill the updater before its normal cleanup completes.
3. Confirm there is no remaining `omarchy-update`, `pacman`, `yay`, or `paru` operation.
4. Run `systemd-inhibit --list`; the root-owned `omarchy-update` blocker remains.
5. Run `omarchy update stay awake stop` as the desktop user; it cannot kill the recorded root-owned PID.
6. Select Suspend from the system menu or run `systemctl suspend`; logind refuses the operation because the block inhibitor remains.
### Expected behavior
Update cleanup should reliably terminate its own privileged sleep inhibitor. A later `start` or `stop` invocation should also recover a stale inhibitor after an interrupted update.
### Actual behavior
The root-owned inhibitor survives after the update is gone and blocks suspend indefinitely, until the process is terminated with privilege or the machine is rebooted.
### Likely cause
`omarchy-update-stay-awake start` launches `sudo systemd-inhibit ... &` and stores `$!`. That PID belongs to the privileged `sudo` process by the time cleanup runs. `stop` later attempts an ordinary unprivileged `kill`, suppresses its failure, and cannot release the inhibitor.
This appears hardware-independent. The symptom initially looked like a Dell/NVIDIA suspend problem, but the journal showed no new suspend attempt; after terminating only the stale inhibitor, suspend was unblocked.
### Possible direction
Keep an unprivileged supervisor PID that can be signaled by the user and have it own/reap the privileged child, or make `stop` use the update's established privileged-command boundary to terminate the validated PID. The existing PID start-time check should remain to avoid PID-reuse mistakes.
Related but distinct: #8077 concerns children inheriting the update lock fd. This report concerns the update-owned sleep inhibitor itself surviving cleanup and blocking suspend.
Validation
Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.
Linked
Not linked to any known issue, other report or change yet.
Decision
Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.
- Out of scopeDecided by agents · verified · 2026-10-09 21:11 UTC