Unofficial community reference. Not affiliated with 37signals or the Omacom Foundation. Download Omarchy only from omarchy.org.
omarchylinux.org Unofficial field manual

Hybrid GPU laptop black screen or login loop (AQ_DRM_DEVICES)

Hybrid NVIDIA plus Intel or AMD laptops on Omarchy 4: why a by-path AQ_DRM_DEVICES value login-loops Hyprland, and the colon-free fix that works.

Workaround available Applies to Omarchy 3.x Last verified 2026-09-16 on 4.0.4
Short answer

Unset AQ_DRM_DEVICES first. Aquamarine splits the value on every colon, so a /dev/dri/by-path/pci-0000:01:00.0-card pin leaves zero usable GPUs and Hyprland dies into a silent SDDM loop. Get a TTY with Ctrl+Alt+F2, remove the value from your uwsm session environment, reboot. If you truly need a GPU order, use colon-free cardN names or udev symlinks, set in the session environment, never in hyprland.lua.

On this page
  1. The fix
  2. Verify it worked
  3. Why it happens
  4. If that did not work
  5. Related

You have a laptop with two GPUs, you followed a multi-GPU guide (or an agent did), and now the machine shows a black screen and drops back to the login screen forever. Nothing in the UI tells you why. In the reports this page is built on, the cause is one environment variable with a colon in the wrong place.

The fix

  1. Get a text console. Press Ctrl + Alt + F2, and try F3 through F6 if that key does nothing. Log in there. The manual covers this under Troubleshooting.

  2. Find out whether anything sets the variable:

    grep -rn AQ_DRM_DEVICES ~/.config/uwsm/ ~/.config/hypr/ /etc/environment 2>/dev/null

    On 4.x, look hardest at ~/.config/uwsm/env.d/*, ~/.config/uwsm/env-hyprland and ~/.config/uwsm/default. If you upgraded from 3.x, check ~/.config/uwsm/env.d/99-omarchy-upgrade-env too: the Quattro upgrader moves the old ~/.config/uwsm/env content into that file, so a 3.x pin comes along for the ride.

  3. If the value contains a colon inside a device name, such as /dev/dri/by-path/pci-0000:01:00.0-card, delete the whole line. Do not try to escape or quote it. An unset variable is safe: Hyprland then picks a GPU on its own.

  4. Reboot. On a muxless laptop that is usually the end of it.

  5. Only if you actually need a specific GPU order, write a colon-free value. List the real nodes first:

    ls -l /dev/dri/by-path/
    readlink -f /dev/dri/by-path/pci-0000:01:00.0-card

    Then put the resolved node names, separated by a single colon, into a new file ~/.config/uwsm/env.d/50-gpu:

    export AQ_DRM_DEVICES=/dev/dri/card1:/dev/dri/card0

    The first entry is the render-primary. On a hybrid machine list both cards. christianjgilman warns on issue #10350 that pinning only one GPU takes down every output wired to the other, and a reader of issue #1776 hit exactly that: after copying a one-card pin, the laptop stopped seeing any external monitor.

  6. cardN numbers can move between boots. Both reporters on issue #8776 give each card a stable, colon-free name with a udev rule keyed on its PCI address, the same approach itsmedardan scripted for 3.x on issue #1776. Take the addresses and vendor IDs from lspci -nn | grep -i vga; the ones below are examples. Put the rule in /etc/udev/rules.d/60-drm-names.rules:

    SUBSYSTEM=="drm", KERNEL=="card[0-9]*", KERNELS=="0000:01:00.0", ATTRS{vendor}=="0x10de", SYMLINK+="dri/dgpu"
    SUBSYSTEM=="drm", KERNEL=="card[0-9]*", KERNELS=="0000:00:02.0", ATTRS{vendor}=="0x8086", SYMLINK+="dri/igpu"

    Then the pin reads AQ_DRM_DEVICES=/dev/dri/dgpu:/dev/dri/igpu, which no parser can mangle. Note the rule lives on the root subvolume while the env file lives on /home, so a snapshot restore can delete one and keep the other.

On 3.x the same variable belonged in ~/.config/uwsm/env, which was a user-owned file. On 4.x that file was retired into /usr/share/uwsm/env.d/10-omarchy, and your overrides go in ~/.config/uwsm/env.d/, which is what the manual FAQ chapter also tells you for other session variables.

Verify it worked

Log in, then check what the compositor actually received:

tr '\0' '\n' < /proc/$(pgrep -x Hyprland | head -1)/environ | grep '^AQ_'
systemctl --user show-environment | grep '^AQ_'

Either both agree with what you wrote, or both are empty. Anything else means something in the session is still rewriting it.

Then confirm the old failure is gone:

journalctl -b | grep -iE 'found no gpus|CBackend::create'

That should return nothing. If you set an NVIDIA-first order deliberately, nvidia-smi is the check: christianjgilman reports Hyprland holding roughly 145 MiB of VRAM once it renders on the dGPU, against about 1 MiB before.

Why it happens

Aquamarine, Hyprland’s backend library, parses AQ_DRM_DEVICES by splitting on the : character. The triage on issue #8776 cites Aquamarine 0.14.0 doing this in src/backend/drm/DRM.cpp. A by-path name already contains two colons from the PCI address, so it is chopped into fragments, every fragment fails to resolve to a real file, and the explicit device list ends up empty. Once the variable exists at all, Aquamarine takes the explicit branch unconditionally and never falls back to automatic selection, so the result is fatal rather than degraded: drm: Found no gpus to use, cannot continue, then CBackend::create() failed!, then SDDM autologin restarts the whole cycle with nothing on screen.

The trap is that the Hyprland wiki’s own detection step produces exactly that by-path string. Two unrelated machines hit this the same way in issue #8776, a dual-AMD desktop and a muxless MSI laptop, both because an AI agent followed the documented detection step and pasted the output into the documented variable.

Omarchy does not set the variable itself. We grepped the whole v4.0.4 source tree for AQ_ and found nothing in bin/, default/, config/ or install/. What Omarchy does ship for NVIDIA is default/hypr/nvidia.lua, which sets NVD_BACKEND, LIBVA_DRIVER_NAME and __GLX_VENDOR_LIBRARY_NAME when it detects an NVIDIA card. On 4.0.0 even those never landed: seanymc85 showed in issue #7755 that os.execute() inside Hyprland’s Lua config always returns “No child processes”, so every detection branch was skipped. The 4.0.1 release notes carry the fix (PR #6939), and default/hypr/helpers.lua in 4.0.4 reads an OK marker from io.popen instead of an exit status. The lesson survives the fix: anything Aquamarine needs at backend startup has to be in the session environment, not in Lua.

A second, rarer failure mode is ordering rather than syntax. On an Optimus laptop Hyprland’s default render primary is normally the iGPU. When the external monitors hang off the dGPU, every frame needs a cross-GPU copy, and christianjgilman’s issue #10350 shows that stalling i915 into a GPU hang that aborts the compositor: Resetting rcs0 for preemption time out followed by context reset due to GPU hang. Putting the NVIDIA node first fixed it there, verified over multi-hour use.

If that did not work

  • The black screen started right after updating to 4.0.4, and you never touched any config. That is likely the kernel change, not this. 4.0.4 makes linux-omarchy the default boot entry, and Nord-Nogare reports in issue #12187 that a hybrid laptop on the prebuilt nvidia-open package has no modules for it, so the desktop hard-freezes about five seconds after login. Omarchy’s own installer uses nvidia-open-dkms, which builds against every installed kernel, so this bites machines where the prebuilt package was swapped in. Pick the stock linux entry in the Limine menu and boot that. See /releases/v4.0.4/ and /fix/nvidia-drivers-omarchy-4/.
  • AMD Strix Point or Radeon 890M, black screen on a fresh install. codyoss’s issue #9720 reports Aquamarine failing its atomic commit with Cannot allocate memory. The reported workaround is AQ_NO_ATOMIC=1 and WLR_NO_HARDWARE_CURSORS=1, again exported from the session environment, not Lua.
  • The machine boots fine, then freezes randomly 20 to 30 minutes in. commandlinetips’s issue #3242 pins that on NVIDIA runtime power management, fixed there with options nvidia NVreg_DynamicPowerManagement=0x00 in /etc/modprobe.d/ plus a udev rule forcing power/control=on, then sudo mkinitcpio -P.
  • Video is corrupted or the browser stutters, but nothing goes black. That is the LIBVA_DRIVER_NAME family, not this one. Start at /fix/chromium-flicker-hardware-acceleration/.
  • You are filing a report. omarchy debug in 4.0.4 does not capture AQ_DRM_DEVICES at all, so paste the two commands from the verify section by hand. PR #9063 would add that dump and PR #8786 would sanitize the value at session-env load, but neither was merged as of 4.0.4, which is why this page says workaround rather than fixed.

Evidence for the ordering half of this page is thinner than for the colon half. The colon bug is confirmed against Aquamarine source in the triage comment on issue #8776 and reproduced on two machines. The NVIDIA-first ordering result is one careful report on one Pascal laptop, and its working line used the by-path form with colons, which did not loop that machine on Aquamarine 0.14.0. A later comment on issue #10350 from RajdeepVerma reports the same string fatal on Aquamarine 0.15.0, resolves it with readlink -f at session-environment time instead, and adds that with NVIDIA as primary his iGPU-driven internal panel needed AQ_MGPU_NO_EXPLICIT=1 or its atomic commit failed with Invalid argument (issue #12289). One machine each, so treat both as leads, not rules.

Upstream threads about this error

15 issues on the Omarchy tracker match this error cluster. Newest fixes often appear as comments on the most-discussed threads.

IssueStateCommentsOpened
#1776 Laptop / Hybrid GPU Power Management Issue (NVIDIA, iGPU + dGPU)closed152025-09-18
#550 Screen goes black during boot with hybrid GPUclosed172025-08-07
#1125 Cannot Recover from Suspense Modeopen112025-08-26
#2132 Cursor lag on dual monitor setup with NVIDIA (RTX 4090) - Solution includedclosed22025-10-01
#8776 Dual-GPU AMD: PCI by-path in AQ_DRM_DEVICES silently login-loops SDDM autologinopen42026-08-28
#2575 Laggy external monitor on a laptopclosed32025-10-19
#10433 install/hardware/nvidia.sh never enables nvidia-suspend/resume/hibernate services, leaving stale GPU memory after suspend (causes Chromium renderer SIGILL crashes)open32026-09-06
#11173 nvidia.lua forces LIBVA_DRIVER_NAME=nvidia on hybrid laptops where the iGPU drives the displays, breaking browser video (repro of #11168 on Arrow Lake + Blackwell)open32026-09-10
#5724 Hyprland crashes on charger unplug — hybrid GPU (Intel iGPU + NVIDIA dGPU) power switch not handledclosed12026-05-10
#10350 Hybrid Pascal (nvidia-580xx) + Intel iGPU: Hyprland crashes when dGPU-driven external monitors are actively used — i915 rcs0 GPU hang; NVIDIA-first AQ_DRM_DEVICES fixes itopen12026-09-05

Accepted answers upstream

Questions people ask

Does Omarchy set AQ_DRM_DEVICES for me?
No. We grepped the whole 4.0.4 tree and the string does not appear in bin/, default/, config/ or install/. If it is set on your machine, you, a guide, or an AI agent put it there. That is also what the triage comment on issue #8776 says.
Will a Limine snapshot rollback fix it?
Usually not. The value normally lives in ~/.config/uwsm, which is on the @home subvolume, and snapshots of the root subvolume do not revert it. slhuckstead makes this point on issue #8776: because the file sits on @home, each older snapshot in the Limine menu boots with the same bad pin.
Can I just put the pin in hyprland.lua?
Not reliably. Aquamarine reads AQ_DRM_DEVICES and AQ_NO_ATOMIC from the process environment before Hyprland parses any Lua, so hl.env() runs too late. Issue #9720 and PR #8786 both say so, and the #8776 report describes a Lua pin as sometimes late but often still applied, which is worse than a clean miss. Use ~/.config/uwsm/env.d instead.

Sources and credit

Fixes on this page were worked out by mowgli42 (Reported the dual-AMD login loop and traced it to Aquamarine splitting AQ_DRM_DEVICES on every colon, with the udev symlink pin that avoids it), Elshayib (Opened the session-environment sanitizer PR and the omarchy debug warning PR), slhuckstead (Reproduced it on a muxless NVIDIA laptop and showed that snapshots on @home inherit the broken value, plus the colon-free udev symlink approach), christianjgilman (Measured that an NVIDIA-first device order stops i915 GPU hangs on Optimus laptops driving externals from the dGPU), codyoss (Documented that Aquamarine reads its env vars before Hyprland parses Lua, so the pin has to live in the session environment), seanymc85 (Found that os.execute() could not report exit status inside Hyprland's Lua config on 4.0.0, so nvidia.lua silently set nothing until 4.0.1). Text here is our own paraphrase; follow the links for the original threads.

Unofficial. Verify against the official manual for your version. Improve this page Markdown version Sources