Skip to content

Improve error handle-ability with Lua require - #14937

Merged
vaxerski merged 2 commits into
hyprwm:mainfrom
LRitzdorf:lua-require-actually-error
Jun 5, 2026
Merged

Improve error handle-ability with Lua require#14937
vaxerski merged 2 commits into
hyprwm:mainfrom
LRitzdorf:lua-require-actually-error

Conversation

@LRitzdorf

@LRitzdorf LRitzdorf commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Normally, require uses Lua's pcall facility to catch any errors, increasing reliability if the user splits their config into modules. Any errors from within those modules are sent to the config manager for eventual display in the config-errors bar.

However, this use of pcall also catches the error case where the user tries to require a nonexistent module. This forcibly displays a message to the user, while also making it impossible to catch or detect such errors from within Lua itself (i.e. pcall(require, "nonexistent") always indicates success).

This PR makes require throw a proper error if module resolution fails, while still hiding (and adding to the config-errors list) any other errors that occur from inside the required module.

Would love feedback on a few details I'm not sure about:

  • Currently, I detect module-resolution errors (as opposed to execution-time errors within the require'd module) just via string comparison, which feels kind of wrong. However, I don't think Lua gives us enough information to do this any other way β€” even the C return value from lua_pcall() is identical between the "nonexistent module" and "erroring module" cases (it's LUA_ERRRUN, specifically).
  • Nested requires produce somewhat strange-looking error messages. I thiiiink this is probably okay, since it should still be clear where the error came from, but maybe we want to clean this up somehow?

Fixes #14534


Edit: This PR also makes Lua's original require available as __require, in case advanced users want to bypass Hyprland's error catching completely.

`require` uses pcall to catch errors and display them to the user. This
is usually okay, but it also hides errors if Lua tries to load a
nonexistent module, which the Lua config might actually want to detect
and handle on its own (e.g. by loading a different module, or disabling
functionality).

Ref hyprwm#14534
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Hello and thank you for making a PR to Hyprland!

Please check the PR Guidelines and make sure your PR follows them.
It will make the entire review process faster. :)

If your code can be tested, please always add tests. See more here.

beep boop, I'm just a bot. A real human will review your PR soon.

@LRitzdorf

Copy link
Copy Markdown
Contributor Author

Just to clarify some behavior here:

  • require("broken") has no change in behavior. It sends errors from within a broken module to the config manager's error list, and successfully returns an empty table.
  • require("nonexistent") now throws an error. As with all other errors, this can be caught via pcall(), and if not it will stop execution of whatever Lua module contains it.
    • If this containing module was loaded via require as well, that require acts as in the "broken" case above.

@LRitzdorf
LRitzdorf marked this pull request as ready for review June 3, 2026 05:00
@Dregu

Dregu commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

I'll try to remember to test this in a few hours with more notes, I've had several issues with safeLuaRequire, all of which are fixed by bypassing safeLuaRequire...

@Dregu

Dregu commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Yep this fixed my own optional requires with pcall and also all issues with a few 3rd party modules that apparently use pcall(require), like lua-posix.

@LRitzdorf

Copy link
Copy Markdown
Contributor Author

Yeah, this will still have nonstandard behavior in a few cases that might matter (i.e. ones where an existing but broken module is required). I wish there were a better way to handle this, like falling back to the standard Lua require for non-Hyprland Lua modules? But I don't think we can really detect what counts as a "Hyprland" module versus a system-provided one. AFAIK, we can't even ask Lua what path it found a given module at.

The alternative is to have some kind of additional input from the user β€” like a new safeRequire Lua command that calls safeLuaRequire(), or an optional protect = true argument to the existing require. But that means everyone has to update their configs to use it, which is maybe not ideal, so soon after the initial switch to Lua.

@Dregu

Dregu commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

I'd be happy enough if vanilla require was just renamed to __require so it's still available if needed.

@LRitzdorf

Copy link
Copy Markdown
Contributor Author

I mean, I could add that to this PR very easily. But also, it'd only work for contexts where you can modify the Lua yourself, which doesn't include third-party modules like you mentioned above...

@Dregu

Dregu commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Unless the first line in your config is require = __require, now everything uses vanilla require.

@LRitzdorf LRitzdorf changed the title Make Lua require throw a detectable error for nonexistent modules Improve error handle-ability with Lua require Jun 3, 2026
If `safeLuaRequire()`'s error-catching behavior isn't wanted, this
allows the user to call the original version directly, as `__require`.
Or, they could bring it back as the default by doing e.g.
`require = __require`, which might be desired to avoid breaking
third-party modules that want to catch errors during module load.
@LRitzdorf
LRitzdorf force-pushed the lua-require-actually-error branch from 154a5e2 to 9d152e5 Compare June 3, 2026 20:06

@vaxerski vaxerski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm thanks

@vaxerski
vaxerski merged commit fcbbd6d into hyprwm:main Jun 5, 2026
9 checks passed
@LRitzdorf
LRitzdorf deleted the lua-require-actually-error branch June 5, 2026 22:42
Psilocybin78 pushed a commit to Psilocybin78/Singularity-compositor that referenced this pull request Jul 3, 2026
…4937)

* config/lua: make `require` throw an actual error for nonexistent modules

`require` uses pcall to catch errors and display them to the user. This
is usually okay, but it also hides errors if Lua tries to load a
nonexistent module, which the Lua config might actually want to detect
and handle on its own (e.g. by loading a different module, or disabling
functionality).

Ref hyprwm#14534

* config/lua: make vanilla `require` available as `__require`

If `safeLuaRequire()`'s error-catching behavior isn't wanted, this
allows the user to call the original version directly, as `__require`.
Or, they could bring it back as the default by doing e.g.
`require = __require`, which might be desired to avoid breaking
third-party modules that want to catch errors during module load.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants