# attempt to index a nil value (global 'o')
Hyprland starts with no bindings, no monitors and a config-error banner after Quattro. Your hyprland.lua never loads Omarchy's helpers, so the global o is nil.
> **Short answer:** Your ~/.config/hypr/hyprland.lua is an old copy that never loads Omarchy's helpers, so the global o is nil and every default module fails. Switch to a TTY with Ctrl+Alt+F2 and run omarchy refresh hyprland, which backs up your file and restores the stock entrypoint. Then re-add your personal lines to hypr/bindings.lua and hypr/monitors.lua instead.
- Applies to Omarchy: 3.x and later
- Status: workaround
- Last verified: 2026-09-16
- Canonical: https://omarchylinux.org/fix/hyprland-lua-attempt-to-index-nil-global-o/
_Unofficial community page. Not affiliated with 37signals or the Omacom Foundation. Omarchy is a registered trademark of 37signals LLC._

Hyprland comes up with the red config-error banner, no keybindings, no monitor layout and no autostarted apps. `hyprctl configerrors` lists the same message once per Omarchy module:

```
require("default.hypr.autostart"): .../default/hypr/autostart.lua:1: attempt to index a nil value (global 'o')
require("default.hypr.bindings.media"): .../media.lua:2: attempt to index a nil value (global 'o')
```

The file at fault is always `~/.config/hypr/hyprland.lua`, not the module the error names.

## The fix

You probably cannot open the Omarchy menu or a terminal, because the bindings that launch them never loaded. Get a text console first.

1. Press `Ctrl + Alt + F2` and log in at the TTY prompt.
2. Look at the top of your entrypoint:

   ```bash
   head -15 ~/.config/hypr/hyprland.lua
   ```

   A healthy 4.x file has a `dofile(...)` line ending in `/default/hypr/bootstrap.lua` near the top and, about ten lines down, `require("default.hypr.omarchy")`. If either is missing, that is your bug.
3. Restore the shipped entrypoint:

   ```bash
   omarchy refresh hyprland
   ```

   This runs `omarchy-refresh-hyprland`, which copies each of `hyprland.lua`, `bindings.lua`, `monitors.lua`, `input.lua`, `looknfeel.lua`, `autostart.lua` and `.luarc.json` from `/usr/share/omarchy/config/hypr` into `~/.config/hypr`. Every file it replaces is saved first as `<file>.bak.<unix-timestamp>` in the same directory, and the command prints a diff of what changed.
4. Log out and back in, or reboot.
5. Copy your personal lines out of the `.bak.` files into `~/.config/hypr/bindings.lua` and `~/.config/hypr/monitors.lua`. Do not put them back into `hyprland.lua`. The stock entrypoint loads those override files after the defaults for exactly this reason.

### If you want to keep your hyprland.lua as it is

Two lines are enough. Edit `~/.config/hypr/hyprland.lua` from the TTY and make sure the top of the file reads:

```lua
dofile((os.getenv("OMARCHY_PATH") or "/usr/share/omarchy") .. "/default/hypr/bootstrap.lua")

require("default.hypr.omarchy")
```

Everything that uses `o` must come after those, including your own `require("hypr.bindings")` and any `o.window(...)` you added at the bottom. Then log out and back in.

If your file still carries the older 4.0 alpha preamble (a hand-built `package.path = ...` block and `require("default.hypr.paths")`), the minimal repair people used in May 2026 was to add `require("default.hypr.helpers")` before the first `require("default.hypr.*")` line. That works, but on 4.0.4 you are better off moving to the bootstrap `dofile`, because the bootstrap also adds `~/.local/state/?.lua` to the search path, and on 4.0.4 the current theme's Hyprland module is loaded from `~/.local/state/omarchy/current/theme/`.

## Verify it worked

From a graphical session:

```bash
hyprctl reload
hyprctl configerrors
```

Omarchy's own agent notes use that pair as the validation step after any Lua config change. A clean result prints no errors. Then check that the things that were missing are back: `Super + K` opens the keybindings list, `Super + Space` opens the menu, and your wallpaper and bar are up.

## Why it happens

In Quattro the global `o` is not a Hyprland builtin. It is created by `/usr/share/omarchy/default/hypr/helpers.lua`, which starts with `o = o or {}` and then hangs `o.bind`, `o.window`, `o.launch_on_start` and the rest off that table. Nothing else defines it. `helpers.lua` is the first module `default/hypr/omarchy.lua` requires, and `default.hypr.omarchy` is the one line through which the shipped `hyprland.lua` loads every default.

So `o` is nil whenever your entrypoint reaches a default module without going through `default.hypr.omarchy` first. Three real ways that happens:

- **You carried an old `hyprland.lua` forward.** A file written during the 4.0 alpha requires `default.hypr.autostart` and friends directly, with no helpers line. This is what issue #5879 documents, and what issues #5814, #5822 and #5824 were all hitting in May 2026 on the dev channel and 4.0 alpha builds.
- **Your `package.path` still points at the 3.x location.** Before 4.0, `OMARCHY_PATH` was `$HOME/.local/share/omarchy`. On 4.x it is `/usr/share/omarchy`, because Omarchy is a pacman package now. A restored dotfiles copy of the old preamble searches a directory that no longer holds the defaults, so every `require("default.hypr.*")` fails and `o` never gets defined.
- **You reordered the requires.** Putting `require("hypr.bindings")` above `require("default.hypr.omarchy")` runs your `o.bind` calls before `o` exists.

Omarchy ships migration `1781063758.sh` ("Update Hyprland Lua entrypoint to load Omarchy bootstrap", dated 2026-06-10) to rewrite the old preamble into the bootstrap `dofile` automatically. It is present in every 4.0.x tag from 4.0.0 through 4.0.4. It skips any file that already contains `/default/hypr/bootstrap.lua`, which is why fresh 4.0 installs are never affected.

The migration is also why this page says workaround rather than fixed. Issue #7103, filed by an automated QA pass in August 2026 and still open, shows that once the migration's awk has matched the old preamble, it discards input until it meets a line that is exactly `.. package.path`. If you had rewrapped that assignment or appended your own path entry, no line matches, the discard runs to the end of the file, and a two-line config is written back with no backup. PR #11222 rewrites it to consume the assignment by its continuation lines and to save a copy as `hyprland.lua.omarchy-bootstrap.bak` first. That PR was still open on 2026-09-16.

## What changed between 3.x and 4.x

On 3.8.4, the last 3.x release, `~/.config/hypr` held `hyprland.conf`, `bindings.conf`, `monitors.conf` and the rest. There was no Lua and no `o`. The May 2026 reports in this cluster came from people on the dev channel or 4.0 alpha builds running a pre-release Lua config against Hyprland 0.55, and dhh's answer at the time was to go back to the stable channel via *Update > Channel > Stable*. That advice is dead on 4.x. Quattro moved the whole config to Lua, and there is no `.conf` path to fall back to.

## If that did not work

- **Still broken after the refresh.** Two people in issue #5879 reported that only removing the whole directory worked. Move it aside rather than deleting it: `mv ~/.config/hypr ~/hypr.broken && omarchy refresh hyprland`, then reboot and pull your edits back from `~/hypr.broken`.
- **Your `hyprland.lua` is now two lines long.** That is issue #7103. Omarchy's Snapper config covers the root subvolume only (`SUBVOLUME="/"` in `default/snapper/root`), and PR #11222 notes that `/home` is not in the pre-update snapshot. In practice `omarchy refresh hyprland` plus rewriting your bindings is the recovery.
- **A different Lua error.** A `Runtime error in lua` popup after unbinding a key is [issue #9005](https://github.com/omacom/omarchy/issues/9005), and a `bad_any_cast` crash on mouse input under Hyprland 0.56.2 is [issue #10912](https://github.com/omacom/omarchy/issues/10912). Both were open on 2026-09-16 and neither is a missing `o`.
- **The error appeared during an update rather than after one.** See [/fix/migration-failed-mid-update/](/fix/migration-failed-mid-update/).

The manual chapter that covers these files is [Dotfiles](https://omarchy.org/manual/dotfiles/). It lists what each `~/.config/hypr/*.lua` file is for and shows the `hl.unbind` plus `o.bind` pattern for replacing a default binding.

## Related

- [/fix/custom-keybindings-lost-after-quattro/](/fix/custom-keybindings-lost-after-quattro/)
- [/fix/monitors-conf-replaced-by-monitors-lua/](/fix/monitors-conf-replaced-by-monitors-lua/)
- [/reference/hyprland-conf-to-lua-migration/](/reference/hyprland-conf-to-lua-migration/)
- [/upgrade/3-to-4-quattro/](/upgrade/3-to-4-quattro/)
- [/upgrade/what-migrations-do/](/upgrade/what-migrations-do/)
- [/reference/commands/omarchy-refresh-hyprland/](/reference/commands/omarchy-refresh-hyprland/)

## Sources

- [Issue #5879: Existing ~/.config/hypr/hyprland.lua not migrated to load default.hypr.helpers after 4.0 update](https://github.com/omacom/omarchy/issues/5879)
- [Issue #5822: dev commit e916491c9f1805be292ed274e59d99921c71398b breaks all hyprland lua files](https://github.com/omacom/omarchy/issues/5822)
- [Issue #5814: hyprland user config broken](https://github.com/omacom/omarchy/issues/5814)
- [Issue #5824: New update breaks hyperland](https://github.com/omacom/omarchy/issues/5824)
- [Issue #5911: Missing migration: helpers.lua not loaded in existing hyprland.lua after update](https://github.com/omacom/omarchy/issues/5911)
- [Issue #7103: Migration 1781063758 can truncate a customized hyprland.lua to two lines](https://github.com/omacom/omarchy/issues/7103)
- [PR #11222: Stop the bootstrap migration truncating a customized hyprland.lua](https://github.com/omacom/omarchy/pull/11222)
- [Omarchy Manual: Dotfiles](https://omarchy.org/manual/dotfiles/)
