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.
omarchy-menu-keybindings hangs forever when a user Lua config iterates hl.get_monitors()
Reported by e-defix · filed Aug 15, 2026 · open at source
At a glance
- 1 · What is claimed?
- ConfirmedViolates SW-REQ-260922-0W96: With user config that iterates hl.get_monitors() via ipairs, the keybindings menu shows no binds at all: the lua bind scan never completes, so the source-derived cache is never built and the menu never opens - the binds are never shown nor dispatchable.
- ConfirmedViolates SYS-REQ-260922-6642: omarchy-menu-keybindings --print hangs indefinitely: it performs neither its documented side effect (print the binding list) nor a loud, exit-coded refusal.
- ConfirmedReproducible: A user Hyprland Lua config that iterates hl.get_monitors() with ipairs at load time hangs omarchy-menu-keybindings --print indefinitely; only an external timeout ends it.
- ConfirmedAffects the menu component
- 2 · What does it affect?
- 3 · Is it reproducible?
- An engine-executed run exited 1 and showed the defect signal. See reproducer
- 4 · What remains unclear?
- Nothing recorded as open.
- 5 · What happens next?
- Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. So far: in the audited area (menu) — decided by agents · verified; matches no known issue — decided by agents · verified. The outcome (valid, duplicate, not a bug, …) is not decided yet. See the decision.
Original report
What happened
omarchy-menu-keybindings (SUPER + K) never opens. The process hangs indefinitely — no menu, no error, no timeout. omarchy-menu-keybindings --print also hangs.
The hang is triggered by any user Lua config that iterates one of Hyprland's list getters (hl.get_monitors(), hl.get_windows(), hl.get_workspaces()) with ipairs at config-evaluation time.
What I expected
The keybindings menu opens and lists the bindings, or fails loudly.
Steps to reproduce
On Omarchy 4.0.0 (quattro), add a single line to ~/.config/hypr/monitors.lua:
for _, monitor in ipairs(hl.get_monitors()) do endThen run:
omarchy-menu-keybindings --print # hangs foreverHyprland itself is fine — hyprctl reload and hyprctl configerrors are clean, and the config behaves correctly at runtime. Only the keybindings scanner hangs.
Root cause
build_lua_bind_cache() in omarchy-menu-keybindings re-evaluates ~/.config/hypr/hyprland.lua in a bare lua interpreter, with hl replaced by a catch-all stub (bin/omarchy-menu-keybindings, around lines 181-232):
local noop
noop = setmetatable({}, {
__index = function() return noop end,
__call = function() return noop end,
})Because __index answers every key with a truthy value, hl.get_monitors() returns noop, and ipairs(noop) reads index 1, 2, 3, … without ever hitting nil. Infinite loop inside the lua subprocess. The while read loop feeding off it in bash blocks forever, so the menu never renders.
The stub already special-cases one getter to return a real value:
get_config = function()
return nil
end,The list getters just were not covered.
Suggested fix
Stub the list getters with real empty tables, so iteration terminates:
get_monitors = function() return {} end,
get_windows = function() return {} end,
get_workspaces = function() return {} end,A timeout around the lua subprocess would also turn this class of failure into a degraded menu instead of a silent hang.
Why this probably was not caught
No config under /usr/share/omarchy/default/hypr/ calls any hl.get_* getter at load time (grep -rn "get_monitors\|get_windows\|get_workspaces" /usr/share/omarchy/default/hypr/ returns nothing), so the stock configs never hit it.
Third-party Lua modules do. Unmodified upstream shezdy/hyprsplit init.lua iterates all three getters, so any user requiring it from their Hypr config gets the same hang.
My own trigger was dynamic monitor placement — computing the laptop's position from the live external monitor geometry, rather than hardcoding auto-right.
Workaround
Guard in ~/.config/hypr/hyprland.lua, right after the bootstrap dofile, detecting the stub (raw slot empty but __index conjures a value) and handing back real empty lists:
local probe = hl.get_monitors()
if type(probe) == "table" and rawget(probe, 1) == nil and probe[1] ~= nil then
hl.get_monitors = function() return {} end
hl.get_windows = function() return {} end
hl.get_workspaces = function() return {} end
endWith that in place omarchy-menu-keybindings --print exits 0 and lists all 231 bindings.
System details
- Omarchy 4.0.0-1 (stable channel)
- Hyprland 0.56.2-1
- Lua 5.5.1-1
- CPU: AMD Ryzen AI 7 PRO 350 w/ Radeon 860M
- GPU: AMD Radeon 840M / 860M Graphics (Krackan)
View raw text
### What happened
`omarchy-menu-keybindings` (SUPER + K) never opens. The process hangs indefinitely — no menu, no error, no timeout. `omarchy-menu-keybindings --print` also hangs.
The hang is triggered by any user Lua config that iterates one of Hyprland's list getters (`hl.get_monitors()`, `hl.get_windows()`, `hl.get_workspaces()`) with `ipairs` at config-evaluation time.
### What I expected
The keybindings menu opens and lists the bindings, or fails loudly.
### Steps to reproduce
On Omarchy 4.0.0 (quattro), add a single line to `~/.config/hypr/monitors.lua`:
```lua
for _, monitor in ipairs(hl.get_monitors()) do end
```
Then run:
```bash
omarchy-menu-keybindings --print # hangs forever
```
Hyprland itself is fine — `hyprctl reload` and `hyprctl configerrors` are clean, and the config behaves correctly at runtime. Only the keybindings scanner hangs.
### Root cause
`build_lua_bind_cache()` in `omarchy-menu-keybindings` re-evaluates `~/.config/hypr/hyprland.lua` in a bare `lua` interpreter, with `hl` replaced by a catch-all stub (bin/omarchy-menu-keybindings, around lines 181-232):
```lua
local noop
noop = setmetatable({}, {
__index = function() return noop end,
__call = function() return noop end,
})
```
Because `__index` answers **every** key with a truthy value, `hl.get_monitors()` returns `noop`, and `ipairs(noop)` reads index 1, 2, 3, … without ever hitting `nil`. Infinite loop inside the `lua` subprocess. The `while read` loop feeding off it in bash blocks forever, so the menu never renders.
The stub already special-cases one getter to return a real value:
```lua
get_config = function()
return nil
end,
```
The list getters just were not covered.
### Suggested fix
Stub the list getters with real empty tables, so iteration terminates:
```lua
get_monitors = function() return {} end,
get_windows = function() return {} end,
get_workspaces = function() return {} end,
```
A timeout around the `lua` subprocess would also turn this class of failure into a degraded menu instead of a silent hang.
### Why this probably was not caught
No config under `/usr/share/omarchy/default/hypr/` calls any `hl.get_*` getter at load time (`grep -rn "get_monitors\|get_windows\|get_workspaces" /usr/share/omarchy/default/hypr/` returns nothing), so the stock configs never hit it.
Third-party Lua modules do. Unmodified upstream [shezdy/hyprsplit](https://github.com/shezdy/hyprsplit) `init.lua` iterates all three getters, so any user requiring it from their Hypr config gets the same hang.
My own trigger was dynamic monitor placement — computing the laptop's position from the live external monitor geometry, rather than hardcoding `auto-right`.
### Workaround
Guard in `~/.config/hypr/hyprland.lua`, right after the bootstrap `dofile`, detecting the stub (raw slot empty but `__index` conjures a value) and handing back real empty lists:
```lua
local probe = hl.get_monitors()
if type(probe) == "table" and rawget(probe, 1) == nil and probe[1] ~= nil then
hl.get_monitors = function() return {} end
hl.get_windows = function() return {} end
hl.get_workspaces = function() return {} end
end
```
With that in place `omarchy-menu-keybindings --print` exits 0 and lists all 231 bindings.
### System details
- Omarchy 4.0.0-1 (stable channel)
- Hyprland 0.56.2-1
- Lua 5.5.1-1
- CPU: AMD Ryzen AI 7 PRO 350 w/ Radeon 860M
- GPU: AMD Radeon 840M / 860M Graphics (Krackan)
Also reported as
R-1816 is the earliest report of this defect, filed Aug 15, 2026. 4 later reports describe the same defect.
- Aug 15, 2026R-1816 · this report— the original
- Sep 16, 2026Keybindings menu (SUPER+K) hangs forever if hyprland.lua iterates a hyprlua getter R-498·Decided by agents · verified
Closed upstream on 2026-10-12 by the bot omarchybot, as a duplicate (target not recorded).
- ·Decided by agents · verified
Open upstream.
- Oct 1, 2026Super + K hangs and spawns CPU-bound Lua processes when config iterates hl.get_workspaces() R-2151·Decided by agents · verified
Open upstream.
- ·Decided by agents · verified
Open upstream.
Validation
AI validator opencode-promoter-1 (xiaomi-token-plan-sgp/mimo-v2.6-pro) · evaluated revision 1 at product commit ecae57a237ef · sealed 2026-10-10T05:03:36Z
The report says omarchy-menu-keybindings and --print hang forever when the user Hyprland Lua config iterates an hl list getter (hl.get_monitors(), hl.get_windows(), hl.get_workspaces()) with ipairs at config-evaluation time, while Hyprland itself stays fine. build_lua_bind_cache in bin/omarchy-menu-keybindings re-evaluates ~/.config/hypr/hyprland.lua under a stub hl whose catch-all __index answers every key with a truthy noop sentinel, so ipairs over a list getter never reaches nil and the lua subprocess spins forever; the bash while-read loop feeding off it blocks, and the menu neither opens nor refuses. The reproducer drives the real bin/omarchy-menu-keybindings --print with a stock user config tree plus the reported one line of user Lua, placed ahead of require("default.hypr.omarchy") because at this baseline that require reaches default/hypr/qconsole.lua, whose numeric comparison throws against the same stub and makes the pcall abort the scan before later user files load (the masking the issue thread documents) - the defect is the stub's non-terminating ipairs, reached by any user Lua the scan evaluates. The engine run is killed by the reproducer's own watchdog after 8 seconds and prints the defect-present marker; with the list getters stubbed to real empty tables the same run terminates and lists the bindings. KI-MENU-KEYBINDINGS-SCAN-DOFILE-ABORT is the same stub aborting the scan early on a throwing comparison (later binds silently vanish) rather than never returning; KI-MENU-KEYBINDINGS-NO-TIMEOUT is unbounded waits in hyprctl binds / xkbcli compile-keymap, not the lua subprocess walking the hl stub.
- ConfirmedViolates a requirementBinds Hyprland reports as dispatcher __lua are shown with… SW-REQ-260922-0W96
Violates SW-REQ-260922-0W96: With user config that iterates hl.get_monitors() via ipairs, the keybindings menu shows no binds at all: the lua bind scan never completes, so the source-derived cache is never built and the menu never opens - the binds are never shown nor dispatchable.
Engine: engine-executed run exited 1 and showed the defect signal
What “confirmed” means here: the requirement exists and the engine reproduced the defect. That the reproducer exercises THIS requirement is the validator's argument (see rationale).
Evidence: requirement SW-REQ-260922-0W96 · file pocs/reproducers/a withheld known issue/repro.sh
Validator's rationale (commentary): SW-REQ-260922-0W96: 'Binds Hyprland reports as dispatcher __lua are shown with resolved keys from the source-derived cache and remain dispatchable.' The fretish adds 'the keybindings_menu shall eventually satisfy lua_binds_dispatchable'. A scan that never terminates can never show the binds at all, so the eventual guarantee is violated.
- ConfirmedViolates a requirementMenu action scripts (plugin picker, share, timezone,… SYS-REQ-260922-6642
Violates SYS-REQ-260922-6642: omarchy-menu-keybindings --print hangs indefinitely: it performs neither its documented side effect (print the binding list) nor a loud, exit-coded refusal.
Engine: engine-executed run exited 1 and showed the defect signal
What “confirmed” means here: the requirement exists and the engine reproduced the defect. That the reproducer exercises THIS requirement is the validator's argument (see rationale).
Evidence: requirement SYS-REQ-260922-6642 · file pocs/reproducers/a withheld known issue/repro.sh
Validator's rationale (commentary): SYS-REQ-260922-6642: 'Menu action scripts (plugin picker, share, timezone, images, keybindings, file picker, emoji insert) perform their documented side effect or a loud, exit-coded refusal.' The hang is neither - the silent shape the error_handling obligation grades high.
- ConfirmedReproducible
Reproducible: A user Hyprland Lua config that iterates hl.get_monitors() with ipairs at load time hangs omarchy-menu-keybindings --print indefinitely; only an external timeout ends it.
Engine: engine-executed run exited 1 and showed the defect signal
Evidence: file pocs/reproducers/a withheld known issue/repro.sh
Affects the menu component
Engine: confirmed violation of SW-REQ-260922-0W96, SYS-REQ-260922-6642 owned by menu
Evidence: requirement SW-REQ-260922-0W96 · requirement SYS-REQ-260922-6642 · file pocs/reproducers/a withheld known issue/repro.sh
Engine reference checks at 46fea98725ea (11/11 ok)
- okcommit46fea98725ea6adcc5fe7d1acbb3542f84f580ec
- okbase commitecae57a237ef4b084c234a25835b8145ddc5295d
- okbase ancestryecae57a237ef4b084c234a25835b8145ddc5295d
- okproduct code untouchedthis report's reproducer branch
- okbranchthis report's reproducer branch
- okfilepocs/reproducers/a withheld known issue/repro.sh
- okrequirementSW-REQ-260922-0W96
- okrequirementSYS-REQ-260922-6642
- okcomponentmenu
- okknown issueKI-MENU-KEYBINDINGS-NO-TIMEOUT
- okknown issueKI-MENU-KEYBINDINGS-SCAN-DOFILE-ABORT
The engine's own check, at validation time, that the commits, the reproducer branch (touching only reproducer files), the reproducer files and every mapped requirement / component / known issue really exist.
Validator-authored hypothesis. Each claim's verification is engine-computed: confirmed only from an engine-executed reproducer run recorded in this record, refuted when recorded evidence contradicts it. Prose is commentary. The disposition of the report is a human decision.
Reproducer
bash pocs/reproducers/a withheld known issue/repro.sh
Setup failure: exit 2 means the reproducer could not set up (e.g. the product did not build) — such a run decides nothing.
Defect signal: output contains PROOF-REPRODUCER: defect-present a withheld known issue
PROOF-REPRODUCER: defect-present a withheld known issue
running omarchy-menu-keybindings --print with the reported trigger in the user config exit=124 PROOF-REPRODUCER: defect-present a withheld known issue
Needs: linux · coreutils timeout on PATH · lua interpreter on PATH · ran on linux/amd64 · Runs as a normal user with a throwaway HOME; no Hyprland session is needed because the hang happens in the lua bind scan before any hyprctl call.
Linked
- Fixed bypr/14128· confirmed
- Fixed bypr/12712· confirmed
- Fixed bypr/7564· confirmed
- Fixed bypr/13276· confirmed
- Fixed bypr/11733· confirmed
- Fixed bypr/12155· confirmed
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.
- Decided by agents · verified: in the audited area (menu)
- Decided by agents · verified: matches no known issue
The outcome (valid, duplicate, not a bug, …) is not decided yet.