INC-2026-04-07-002: Hyprland Built-in Keyboard Failure on modestus-razer
Incident Summary
| Field | Value |
|---|---|
Detected |
2026-04-07 06:23 PST |
Mitigated |
2026-04-07 ~11:00 PST (manual symlink recreated) |
Resolved |
2026-04-07 ~11:15 PST (root cause identified, permanent fix designed) |
Duration |
~5 hours (3+ hours active investigation) |
Severity |
P2 (High) — Primary workstation built-in keyboard non-functional in compositor. |
Impact |
Razer Blade built-in keyboard unusable in Hyprland. All keybinds dead. External Kinesis Advantage 360 Pro worked as workaround. |
Root Cause |
Commit |
Environment
| Property | Value |
|---|---|
Machine |
modestus-razer (Razer Blade 18 2025) |
CPU |
Intel Core Ultra 9 275HX (24 cores) |
GPU |
Intel Arrow Lake-S iGPU + NVIDIA RTX 5090 Max-Q |
Kernel |
6.19.11-arch1-1 |
Hyprland |
0.54.3-2 |
Built-in Keyboard |
Razer Razer Blade (USB 1532:02C7, 3 HID interfaces) |
External Keyboard |
Kinesis Advantage 360 Pro (USB 1D50:615E, uhid virtual HID) |
Dotfiles Repo |
dots-quantum (GNU Stow managed, |
Root Cause
The Stow Architecture
~/.config/hypr is not a directory — it is a symlink to the stow package:
~/.config/hypr → ../atelier/_projects/personal/dots-quantum/hyprland/.config/hypr
This means every file Hyprland reads from ~/.config/hypr/ is actually read from the dots-quantum git repository. If a file is deleted from git, it disappears from the deployed config immediately.
The Breaking Change
Commit 64253e7 (fix(dotfiles): Guard .zshenv cargo source, harden gitignore, fix gitconfig portability) deleted the env-gpu.conf symlink from the hyprland stow package:
diff --git a/hyprland/.config/hypr/env-gpu.conf b/hyprland/.config/hypr/env-gpu.conf deleted file mode 120000 --- a/hyprland/.config/hypr/env-gpu.conf +++ /dev/null @@ -1 +0,0 @@ -/home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf
The commit message says "Untrack env-gpu.conf (already gitignored, was tracked before gitignore entry)." The intent was cleanup — the file was gitignored AND tracked, which is contradictory. But deleting it from git also deleted it from the stow package, which deleted it from the deployed config.
The Cascade
-
env-gpu.confremoved from stow package directory -
~/.config/hypr/env-gpu.confceases to exist (directory symlink) -
hyprland.confline 113:source = ~/.config/hypr/env-gpu.conffails — file not found -
Hyprland starts without GPU environment variables:
-
No
LIBVA_DRIVER_NAME=nvidia -
No
__GLX_VENDOR_LIBRARY_NAME=nvidia -
No
GBM_BACKEND=nvidia-drm -
No
WLR_NO_HARDWARE_CURSORS=0 -
No
__NV_PRIME_RENDER_OFFLOAD=1
-
-
Compositor initializes on Intel iGPU in degraded mode
-
USB HID keyboard (Razer, on the NVIDIA GPU’s USB controller) does not deliver input events to the compositor
-
Virtual HID keyboard (Kinesis, via uhid on the Intel USB controller) continues to work
Proof
At commit 34065dc (before the deletion): env-gpu.conf symlink existed in stow package. Hyprland sourced it. Source line errored because the symlink target (hosts/razer/) didn’t exist at that older commit, BUT the error caused Hyprland to skip GPU config entirely — and the built-in keyboard worked. This is because without GPU config, Hyprland defaulted to a working state.
At main (after the deletion): env-gpu.conf doesn’t exist in the stow package at all. Same source error. But when the symlink was manually recreated pointing to the correct hosts/razer/env-gpu.conf (which now exists at main), the GPU config loaded and the keyboard worked.
Empty config test (Hyprland -c /dev/null): Built-in keyboard did NOT work. This initially confused the investigation, but is consistent — with no config at all, Hyprland has no GPU env vars AND no input configuration, defaulting to a state where USB HID is not functional on this hybrid GPU machine.
Timeline
| Time | Event |
|---|---|
~Apr 4 |
Commit |
Apr 6 evening |
On Razer: |
Apr 7 06:23 |
User discovers Super key dead on built-in keyboard. Investigation begins. |
Apr 7 06:30 |
SSH access to Razer established via reverse tunnel (INC-2026-04-07-001). |
Apr 7 06:50-08:00 |
Phase 1-2: Config comparison (md5 identical), session state investigation, package upgrade. All eliminated. |
Apr 7 08:00-08:30 |
Phase 3-4: |
Apr 7 08:30-09:15 |
Phase 5-6: openrazer daemon stopped, razerkbd kernel module unloaded. Raw evdev returns zero bytes from Razer keyboard. Kinesis works. Multiple reboots. |
Apr 7 09:15-10:30 |
Phase 7: |
Apr 7 ~10:40 |
Breakthrough: At commit |
Apr 7 ~11:00 |
Manual symlink recreation: |
Apr 7 ~11:15 |
Root cause confirmed. Permanent fix designed: replace symlink-based sourcing with hostname-based path in |
Investigation Evidence Log
Phase 1: Configuration Comparison (Eliminated as Direct Cause)
md5sum ~/.config/hypr/hyprland.conf # Both machines
790a130e77df802bb6a980b7f09ffe78 (identical on P16g and Razer)
readlink -f ~/.config/hypr/env-gpu.conf # Razer
/home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf
pacman -Q hyprland aquamarine nvidia-utils seatd # Both machines
hyprland 0.54.3-2 aquamarine 0.10.0-4 nvidia-utils 595.58.03-1 seatd 0.9.3-1
Phase 2: Session State (Eliminated)
loginctl list-sessions --no-legend # Pre-reboot
5 accumulated sessions from crash/restart cycles
Two reboots performed. Problem persisted. Session state eliminated.
Phase 3: Device Visibility
hyprctl devices # Initial check
mice: Keyboards: # ZERO devices
ls -la /dev/input/event{4,5,6}
event4: root:input (Kinesis via uhid) event5: root:openrazer (Razer keyboard) event6: root:openrazer (Razer keyboard interface 2)
groups # User group check
# input group NOT present
Fixes Applied (Necessary but Not Sufficient)
sudo usermod -aG input evanusmodestus
sudo tee /etc/udev/rules.d/99-openrazer-input-fix.rules << 'EOF'
SUBSYSTEM=="input", ATTRS{idVendor}=="1532", GROUP="input", MODE="0660"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger
These fixed device visibility (hyprctl devices showed keyboards after reboot) but did NOT fix the input issue.
Phase 4: openrazer Daemon and Kernel Module (Eliminated)
systemctl --user stop openrazer-daemon
systemctl --user disable openrazer-daemon
sudo rmmod razerkbd # Rebind to hid-generic
dmesg | tail -5
hid-generic 0003:1532:02C7.0004: input,hidraw2: USB HID v1.11 Keyboard hid-generic 0003:1532:02C7.0005: input,hidraw3: USB HID v1.11 Mouse
Problem persisted after daemon stop AND module unload. Eliminated.
Phase 5: Raw Event Testing
timeout 3 cat /dev/input/event5 | od -A x -t x1 -N 192
000000 # Zero bytes — Razer keyboard produced no evdev events
# EVIOCGRAB check
python3 -c "import fcntl,struct,os; [print(f'event{e}: NOT grabbed') for e in [4,5,6]]"
No exclusive grab on any device.
fuser -v /dev/input/event4 /dev/input/event5 /dev/input/event6
event4: Hyprland only event5: Hyprland only event6: Hyprland only
Phase 6: USB Device Identity
udevadm info /dev/input/event4
DEVPATH=/devices/virtual/misc/uhid/0005:1D50:615E.0008 ← Kinesis (works)
udevadm info /dev/input/event5
DEVPATH=/devices/pci.../1532:02C7.0003 ID_USB_DRIVER=usbhid ← Razer (broken)
Phase 7: Empty Config Test
pkill -9 Hyprland
echo "" > /tmp/empty.conf
Hyprland -c /tmp/empty.conf
Kinesis: works Razer built-in: does NOT work
Phase 8: Git Bisect (The Breakthrough)
git -C ~/atelier/_projects/personal/dots-quantum checkout 34065dc
stow -R -t ~ hyprland
pkill -9 Hyprland && start-hyprland
Source error: "globbing error: found no match" for env-gpu.conf Built-in keyboard: WORKS
git -C ~/atelier/_projects/personal/dots-quantum checkout main
env-gpu.conf: MISSING from stow package Built-in keyboard: DOES NOT WORK
git -C ~/atelier/_projects/personal/dots-quantum diff 34065dc..main -- hyprland/
diff --git a/hyprland/.config/hypr/env-gpu.conf b/hyprland/.config/hypr/env-gpu.conf deleted file mode 120000 --- a/hyprland/.config/hypr/env-gpu.conf +++ /dev/null @@ -1 +0,0 @@ -/home/.../dots-quantum/hosts/razer/env-gpu.conf
Only change between working and broken: env-gpu.conf symlink deleted from git.
Phase 9: Confirmation
ln -sf /home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf \
~/atelier/_projects/personal/dots-quantum/hyprland/.config/hypr/env-gpu.conf
pkill -9 Hyprland && rm -rf /run/user/1000/hypr/* ~/.cache/hyprland/hyprlandCrash*
start-hyprland
Built-in keyboard: WORKS Super+D: WORKS All keybinds: FUNCTIONAL
Resolution
Immediate Fix (Applied)
Recreated the env-gpu.conf symlink in the stow package:
ln -sf /home/evanusmodestus/atelier/_projects/personal/dots-quantum/hosts/razer/env-gpu.conf \
~/atelier/_projects/personal/dots-quantum/hyprland/.config/hypr/env-gpu.conf
Permanent Fix (Proposed)
Replace the symlink-based GPU config sourcing with hostname-based path resolution. This eliminates the per-machine symlink entirely.
Change hyprland.conf line 113:
- source = ~/.config/hypr/env-gpu.conf
+ source = ~/atelier/_projects/personal/dots-quantum/hosts/$HOST/env-gpu.conf
$HOST is set by zsh to the machine hostname (modestus-razer, modestus-p16g, etc.). Each machine sources its own GPU config automatically. No symlink to manage, no gitignore conflict, no deletion risk.
Requirements:
-
Each machine has
hosts/<hostname>/env-gpu.confin dots-quantum -
Currently exists:
hosts/razer/env-gpu.conf,hosts/p16g/env-gpu.conf -
New machine: create
hosts/<newhostname>/env-gpu.conf -
Hostname dirs must match
$HOST— verify withecho $HOSTon each machine
Cleanup after applying:
# Remove the symlink from stow package (no longer needed)
rm ~/atelier/_projects/personal/dots-quantum/hyprland/.config/hypr/env-gpu.conf
# Remove the gitignore entry for env-gpu.conf
# Edit .gitignore and remove: hyprland/.config/hypr/env-gpu.conf
# Commit the hyprland.conf change
cd ~/atelier/_projects/personal/dots-quantum
git add hyprland/.config/hypr/hyprland.conf .gitignore
git commit -m "fix(hyprland): Source env-gpu.conf by hostname — eliminates per-machine symlink
Replace source = ~/.config/hypr/env-gpu.conf with hostname-based path:
source = ~/...dots-quantum/hosts/\$HOST/env-gpu.conf
Root cause of INC-2026-04-07-002: commit 64253e7 deleted the symlink
from git, which removed it from the stow-deployed config. Without GPU
env vars, Hyprland initialized in degraded mode where USB HID input
devices (built-in keyboard) did not function.
Ref: INC-2026-04-07-002"
Secondary Fix: Waybar Slow Startup
hyprland.conf exec-once lines reference swww-daemon and a wallpaper cycle script. If swww is not installed, these hang and delay waybar and other startup processes.
Options:
-
Install
swwwon all machines:sudo pacman -S swww -
Comment out the swww lines in
hyprland.confif not needed -
Background the wallpaper script: add
&to prevent blocking
Collateral Fixes Applied During Investigation
These were necessary fixes discovered during investigation but were not the root cause:
# User was not in input group (needed for device access)
sudo usermod -aG input evanusmodestus
# openrazer udev rule overrides input group on Razer devices
sudo tee /etc/udev/rules.d/99-openrazer-input-fix.rules << 'EOF'
SUBSYSTEM=="input", ATTRS{idVendor}=="1532", GROUP="input", MODE="0660"
EOF
Investigation Rabbit Holes
Documented for learning. Each was investigated, evidence gathered, and eliminated.
| Hypothesis | Time Spent | Why Eliminated |
|---|---|---|
Stale logind sessions |
30 min |
Two reboots cleared sessions. Problem persisted. |
XDG_SESSION_TYPE=tty |
20 min |
Identical on both machines. P16g works with same value. |
Package version mismatch |
15 min |
All packages identical after upgrade. |
openrazer daemon grabbing devices |
20 min |
Daemon stopped and disabled. Problem persisted. |
razerkbd kernel module |
30 min |
Module unloaded, devices rebound to hid-generic. Problem persisted. |
udev group permissions |
30 min |
Fixed (necessary) but not the root cause. Problem persisted after fix. |
USB device reset |
10 min |
USB unbind/rebind performed. Problem persisted. |
Empty config test |
15 min |
Keyboard didn’t work — misleading because no GPU config = same degraded state. |
Total time in rabbit holes: ~2.5 hours. Root cause found in 15 minutes once the right question was asked (git diff between working and broken commit).
Lessons Learned
What Went Well
-
Reverse SSH tunnel established quickly for remote investigation
-
hyprctl dispatch execworkaround kept machine partially usable -
md5sum comparison eliminated config content early
-
Git checkout of known-good commit was the breakthrough
What Could Be Improved
-
Should have checked file existence first, not file content.
ls ~/.config/hypr/env-gpu.confwould have shown "No such file" immediately. Instead, 2.5 hours was spent comparing checksums of files that existed. -
Should have run
git diffbetween working and broken state in the first 10 minutes. The breaking change was a single file deletion. -
"Empty config" test was misleading. On a hybrid GPU machine, no GPU config ≠ "clean baseline." It means "different broken state."
-
Chased kernel/driver hypotheses too long. User repeatedly said "this worked before the dots-quantum pull." Should have trusted that signal and focused on what the pull changed.
Key Takeaways
|
Diagnostic Commands Reference
# === FIRST: Does the sourced file exist? ===
ls -la ~/.config/hypr/env-gpu.conf
cat ~/.config/hypr/env-gpu.conf | head -3
# === Is ~/.config/hypr a real dir or stow symlink? ===
ls -ld ~/.config/hypr
file ~/.config/hypr
# === What did git change in the hyprland package? ===
git -C ~/atelier/_projects/personal/dots-quantum diff <good-commit>..HEAD -- hyprland/
# === What is the stow package state? ===
ls -la ~/atelier/_projects/personal/dots-quantum/hyprland/.config/hypr/
# === Does Hyprland see keyboards? ===
export HYPRLAND_INSTANCE_SIGNATURE=$(ls /run/user/1000/hypr/ | sort | tail -1)
hyprctl devices | grep -A5 keyboard
# === GPU env vars in compositor process ===
cat /proc/$(pgrep -o Hyprland)/environ | tr '\0' '\n' | grep -E 'GBM|GLX|LIBVA|PRIME|WLR'
# === Hyprland source errors ===
# Visible in startup output or hyprland.log:
# "source= globbing error: found no match"
# === Device permissions ===
ls -la /dev/input/event*
stat -c "%G" /dev/input/event{4,5,6}
Metadata
| Field | Value |
|---|---|
Incident ID |
INC-2026-04-07-002 |
Author |
Evan Rosado |
Created |
2026-04-07 |
Last Updated |
2026-04-07 |
Status |
Resolved |
Root Cause Commit |
|
Fix Commit |
Pending — replace line 113 with |
Post-Incident Review |
Complete |