Skip to content

A user's own binds in ~/.config/hypr/bindings.lua never reach the keybindings menu's Lua scan #13790

Closed as duplicate

Description

@linyiru

What happens

omarchy-menu-keybindings keeps its own Lua scan of the user's config, because Hyprland reports every Lua bind as dispatcher __lua with no arg and no id. The scan dies partway through the shipped config, and the pcall wrapped around it discards the error, so nothing surfaces.

The result is that no bind in ~/.config/hypr/bindings.lua is ever scanned. A user's own binds get no dispatcher recovery and no id in the keybindings menu.

Why

Two things line up:

  1. default/hypr/omarchy.lua:18 is require("default.hypr.qconsole"). Under the scan's noop stub, hl.get_workspace returns a stub table, so in default/hypr/qconsole.lua:123 the mon.scale > 0 test compares a table with a number and throws.
  2. config/hypr/hyprland.lua requires default.hypr.omarchy at line 14 and hypr.bindings at line 21. The throw at step 1 unwinds past line 21.

The 229 default binds registered before line 18 do survive, which is why the menu looks fine on a stock install and why this has gone unnoticed.

Reproduce

# extract the scan from the menu, verbatim
sed -n "/^    lua <<'LUA'\$/,/^LUA\$/p" bin/omarchy-menu-keybindings | sed '1d;$d' >/tmp/scan.lua

# a stock config plus one personal bind, where the comments in the shipped
# bindings.lua tell you to put it
mkdir -p /tmp/h/.config && cp -r config/hypr /tmp/h/.config/hypr
echo 'o.bind("SUPER + ALT + P", "My own bind", "true")' >>/tmp/h/.config/hypr/bindings.lua

env -i PATH="$PATH" HOME=/tmp/h OMARCHY_PATH="$PWD" DEBUG=1 lua /tmp/scan.lua
[DEBUG] lua bind scan failed: .../default/hypr/qconsole.lua:123: attempt to compare number with table

229 lines on stdout, and My own bind is not one of them. Move require("default.hypr.helpers") and require("hypr.bindings") ahead of require("default.hypr.omarchy") in hyprland.lua and it becomes 230 lines with My own bind present, which confirms the load order is what is doing it.

Why it matters beyond the id

A user who renames or translates a bind description in ~/.config/hypr/bindings.lua gets no id for it, so the menu falls back to the description. Since the menu's row pairing and its sort order both key on a name, a renamed bind loses the row it shared and the tier it belonged to. Measured on linyiru:menu-sort-by-bind-id (the follow-up to #12557, which moves those two decisions onto the id), with two chords declaring the same id = "Close window" and a translated description:

# both binds in ~/.config/hypr/bindings.lua, shipped load order
SUPER ALT + Q                       → 關閉視窗
SUPER ALT + W                       → 關閉視窗

# same two binds, load order changed so the scan reaches them
SUPER ALT + W / SUPER ALT + Q       → 關閉視窗

So this gates the bind-id work: the ids are threaded correctly, and a personal config still cannot use them, because the scan never reads the file they are declared in.

Scope

Pre-existing and unrelated to bind ids. I am reporting rather than patching because the fix is a judgement call I would rather not make alone: either the scan's stub grows enough shape for qconsole.lua to survive it, or the scan stops depending on the shipped config loading cleanly, or pcall stops being allowed to fail silently. Happy to implement whichever you prefer.

Verified 2026-09-29 on Arch, Lua 5.5.1, at 647b4a21.

🤖 Generated with Claude Code

Activity

  1. manuaudio commented on Sep 29, 2026

    @manuaudio
    Contributor

    Open PR #13276 ("keep the Lua bind scan alive past qconsole.lua") targets this same failure: the scan dying in qconsole.lua before it reaches ~/.config/hypr/bindings.lua. #12916 (contain the Lua bind scan) is related. Your repro with the personal SUPER + ALT + P bind would make a good check for whichever lands.

  2. linyiru commented on Sep 29, 2026

    @linyiru
    ContributorAuthor

    Duplicate of #13276. Closing, and thank you @manuaudio for the fast redirect.

    @playGitboy's report is the better one: same error at the same line, the same "dies after the defaults and before require("hypr.bindings")" mechanism, plus measurement I did not have (22 of 260 cached rows losing their dispatcher, all of them from bindings.lua) and a downstream consequence I had not thought of, where a virtual keyboard reading the records file falls back to wtype, which Hyprland does not route into its own binds, so the key silently does nothing. #12916 is the other half of the same area, containing the scan rather than teaching the stub to survive it.

    I should not have opened this. I had searched this repo's prior art for exactly this defect on 2026-09-28, found the cluster of open PRs around that scan, and retracted a public promise to file it on those grounds. Filing it today means I acted on that conclusion without re-running the search. Apologies for the noise.

    Taking up your suggestion about the repro, @manuaudio: I turned it into an assertion in the existing test/shell.d/keybindings-menu-test.sh harness and checked that it discriminates, not ok at 647b4a21 and ok at #13276's head 14f7e955. Since llstrk's review of #13276 lists a missing regression test, I have offered it there rather than keeping it here.

    🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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