Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-4952GitHub issuePublicFixed

omarchy-menu-keybindings leaks stuck lua processes (infinite loop in noop stub) hammering CPU

Reported by BigKelLearns · filed Sep 7, 2026Closed upstream on 2026-09-20 by bjarneo via an automated message, as a duplicate of #7025 (R-1816). GitHub close reason: completed.

Received and recorded verbatim. Nothing has been checked yet.

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?
Not yet mapped to any requirement or component.
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?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.

Original report

omarchy-menu-keybindings leaks stuck lua processes (infinite loop in noop stub) hammering CPUrevision 1 · captured 2026-10-04 12:10 UTC via poll

What happened

omarchy-menu-keybindings spawns a lua subprocess that hangs in an infinite loop, pegging a CPU core at ~100%. Each invocation leaks a new stuck lua process that never exits, so they accumulate until the machine is hammered (6 stuck processes = ~600% CPU on an 8-core laptop, load average ~9.6).

Root cause

The noop stub in /usr/share/omarchy/bin/omarchy-menu-keybindings is iterable, so ipairs()/pairs() over it never terminate:

local noop
noop = setmetatable({}, {
  __index = function()
    return noop
  end,
  __call = function()
    return noop
  end,
})

Because __index returns noop for every key (including numeric keys), noop[1], noop[2], … are all non-nil. Any for _, v in ipairs(noop) loops forever.

The trigger is ~/.config/hypr/looknfeel.lua's update_scrolling_column_width(), which does:

for _, monitor in ipairs(hl.get_monitors()) do

In the keybindings scan, hl is a stub whose __index returns noop, so hl.get_monitors() returns noop, and ipairs(noop) never ends.

Steps to reproduce

  1. Have a ~/.config/hypr/looknfeel.lua that calls hl.get_monitors() (e.g. the scrolling column_width auto-adjust pattern).
  2. Run omarchy menu keybindings (or trigger the keybindings menu).
  3. Observe a lua child of omarchy-menu-keybindings spin at ~100% CPU and never exit.

Minimal repro of the core bug:

local noop
noop = setmetatable({}, {
  __index = function() return noop end,
  __call  = function() return noop end,
})
for _ in ipairs(noop) do end  -- never terminates

Expected behavior

The keybindings scan should complete quickly and the lua subprocess should exit.

Suggested fix

Make the noop stub non-iterable by returning nil for numeric keys:

noop = setmetatable({}, {
  __index = function(_, k)
    if type(k) == "number" then return nil end
    return noop
  end,
  __call = function() return noop end,
})

I verified this fix locally: with get_monitors = function() return {} end (or the non-iterable noop), the full config loads cleanly in under a second.

System details

  • Omarchy 4.0.2-1
  • Hyprland 0.56.2
  • Arch Linux, 8-core laptop
View raw text
## What happened

`omarchy-menu-keybindings` spawns a `lua` subprocess that hangs in an infinite loop, pegging a CPU core at ~100%. Each invocation leaks a new stuck `lua` process that never exits, so they accumulate until the machine is hammered (6 stuck processes = ~600% CPU on an 8-core laptop, load average ~9.6).

## Root cause

The `noop` stub in `/usr/share/omarchy/bin/omarchy-menu-keybindings` is iterable, so `ipairs()`/`pairs()` over it never terminate:

```lua
local noop
noop = setmetatable({}, {
  __index = function()
    return noop
  end,
  __call = function()
    return noop
  end,
})
```

Because `__index` returns `noop` for *every* key (including numeric keys), `noop[1]`, `noop[2]`, … are all non-nil. Any `for _, v in ipairs(noop)` loops forever.

The trigger is `~/.config/hypr/looknfeel.lua`'s `update_scrolling_column_width()`, which does:

```lua
for _, monitor in ipairs(hl.get_monitors()) do
```

In the keybindings scan, `hl` is a stub whose `__index` returns `noop`, so `hl.get_monitors()` returns `noop`, and `ipairs(noop)` never ends.

## Steps to reproduce

1. Have a `~/.config/hypr/looknfeel.lua` that calls `hl.get_monitors()` (e.g. the scrolling `column_width` auto-adjust pattern).
2. Run `omarchy menu keybindings` (or trigger the keybindings menu).
3. Observe a `lua` child of `omarchy-menu-keybindings` spin at ~100% CPU and never exit.

Minimal repro of the core bug:

```lua
local noop
noop = setmetatable({}, {
  __index = function() return noop end,
  __call  = function() return noop end,
})
for _ in ipairs(noop) do end  -- never terminates
```

## Expected behavior

The keybindings scan should complete quickly and the `lua` subprocess should exit.

## Suggested fix

Make the `noop` stub non-iterable by returning `nil` for numeric keys:

```lua
noop = setmetatable({}, {
  __index = function(_, k)
    if type(k) == "number" then return nil end
    return noop
  end,
  __call = function() return noop end,
})
```

I verified this fix locally: with `get_monitors = function() return {} end` (or the non-iterable `noop`), the full config loads cleanly in under a second.

## System details

- Omarchy 4.0.2-1
- Hyprland 0.56.2
- Arch Linux, 8-core laptop

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

  • Fixed bypr/12712· confirmed
  • Fixed bypr/7564· 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.

No decision has been recorded yet.