Troubleshooting¶
Practical fixes for the most common JuhRadial MX problems, written as problem -> cause -> fix. Most issues fall into one of six buckets: the daemon will not build, the mouse is not detected, the daemon is not running, the menu shows up in the wrong place, button or thumb-wheel actions do nothing, or haptics and battery are missing.
If you only read one thing: collect the diagnostics below first, then jump to the matching section.
See also: Installation · Configuration · Compositor-Support · Features · FAQ · Architecture
Quick diagnostics¶
Run these first. The output tells you which section you need.
| What to check | Command |
|---|---|
| Is the daemon process alive? | pgrep -a juhradiald |
| Service status (user unit) | systemctl --user status juhradialmx-daemon |
| Live daemon logs | journalctl --user -u juhradialmx-daemon -f |
| Run daemon by hand, verbose | /usr/local/bin/juhradiald --verbose |
| Is the mouse on the USB/Bluetooth bus? | lsusb \| grep -i 046d |
| HID devices the kernel sees | ls /sys/bus/hid/devices/ \| grep -i 046D |
Are you in the input group? |
id -nG \| tr ' ' '\n' \| grep -x input |
| Can the uinput node be opened? | ls -l /dev/uinput |
| Is the injection helper running? | systemctl --user status ydotoold |
| Rust toolchain version | cargo --version |
Tip
The D-Bus identity is bus name org.kde.juhradialmx, object path /org/kde/juhradialmx/Daemon, interface org.kde.juhradialmx.Daemon. You can confirm the daemon is exporting it with:
Build and installation¶
Problem: the build fails on an older distro (Ubuntu 24.04, Debian stable, and similar)¶
Cause. The committed Cargo.lock is lockfile format v4, which needs cargo >= 1.78, and one dependency (toml_edit) needs rustc >= 1.76. Distro Rust packages are frequently older: Ubuntu 24.04 ships 1.75. A too-old cargo produces lockfile or edition errors before anything compiles.
Fix. Install an up-to-date toolchain with rustup. The one-line installer does this automatically when it detects a cargo older than 1.78, but for a manual build do it yourself:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
. "$HOME/.cargo/env"
cargo --version # confirm 1.78 or newer
cd daemon && cargo build --release
If you previously installed the distro rust/cargo packages, the rustup shim in ~/.cargo/bin must come first on your PATH. Open a fresh shell (or re-source ~/.cargo/env) after installing.
Problem: the build fails on missing C headers¶
Cause. The daemon links against system libraries for D-Bus, evdev, and HID. Missing -devel/-dev headers fail the build at the link stage.
Fix. Install the development packages for your distro family. These mirror what the installer pulls in:
| Family | Header packages |
|---|---|
| Fedora / RHEL | dbus-devel systemd-devel libevdev-devel hidapi-devel |
| Arch | dbus systemd-libs libevdev hidapi |
| Debian / Ubuntu | libdbus-1-dev libsystemd-dev libevdev-dev libhidapi-dev |
| openSUSE | dbus-1-devel systemd-devel libevdev-devel libhidapi-devel |
Problem: openSUSE reports gtk4-layer-shell is not available¶
Cause. gtk4-layer-shell is not in every openSUSE repository. The installer treats this as a soft warning (gtk4-layer-shell not available on this repo) and continues.
Fix. It is safe to ignore on most setups. The layer-shell surface is only required for correct menu placement on niri (see niri menu not visible below). If you run niri on openSUSE, add a repository that ships the package (for example the relevant X11:Wayland devel repo) and install it, or fall back to a compositor with native cursor support. On all other compositors JuhRadial MX positions the overlay through XWayland and does not need the package.
Device detection¶
Problem: the mouse is not detected at all¶
Cause. Almost always permissions. The daemon reads hidraw (for HID++) and evdev (for button events) directly, which requires membership in the input group. The udev rules ship GROUP="input" on the Logitech device nodes, so without that group the nodes are unreadable.
Fix.
# 1. Confirm the kernel sees a Logitech device (046d):
lsusb | grep -i 046d
ls /sys/bus/hid/devices/ | grep -i 046D
# 2. Make sure the udev rules are installed (the dev sync script does NOT install them):
sudo install -Dm644 packaging/udev/99-juhradialmx.rules /etc/udev/rules.d/99-juhradialmx.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
# 3. Join the input group, then LOG OUT and back in (group changes need a fresh session):
sudo usermod -aG input "$USER"
Warning
Adding yourself to a group does not affect already-running sessions. You must log out and back in (or reboot). Verify afterwards with id -nG | grep input.
Problem: a USB-cabled or receiver mouse works, but the same mouse over Bluetooth is invisible¶
Cause. A Bluetooth-connected mouse is exposed as a virtual uhid device with no parent that carries idVendor/idProduct. Classic rules like ATTRS{idVendor}=="046d" therefore never match a Bluetooth device, so the node keeps its default root:root 0600 permissions.
Fix. The shipped rules already handle this by matching the parent kernel name instead of the vendor attribute. Bluetooth devices are named <bus>:<VID>:<PID>.<n> (uppercase, bus 0005 = Bluetooth, 0003 = USB), and the rules match KERNELS=="0005:046D:*" and KERNELS=="0003:046D:*" with GROUP="input". If a Bluetooth mouse is still not picked up:
- Confirm the rules file is current (it must contain the
KERNELS=="0005:046D:*"line): - Reinstall the rules and re-trigger as shown above, then re-pair or toggle Bluetooth so the node is recreated under the new rules.
- Confirm group ownership landed on the node:
Note
The effective access grant for these nodes comes from GROUP="input", not from uaccess. A TAG+="uaccess" in a 99-* rule runs too late to take effect, so do not rely on it: being in the input group is what matters.
The daemon will not start¶
Problem: systemctl --user status juhradialmx-daemon shows failed or inactive¶
Cause. Several possibilities: the binary is missing, the user has no graphical session/D-Bus when the unit starts, or the daemon hit its restart limit after repeated crashes.
Fix. Work through it with the service tooling:
# Full status plus the last lines of output:
systemctl --user status juhradialmx-daemon
# Follow the logs while you reproduce the issue:
journalctl --user -u juhradialmx-daemon -f
# Reload unit files, then re-enable and start:
systemctl --user daemon-reload
systemctl --user enable --now juhradialmx-daemon
Things to check against the symptoms in the logs:
exec format/ file not found: the binary is not at/usr/local/bin/juhradiald. Re-run the installer orsudo install -Dm755 daemon/target/release/juhradiald /usr/local/bin/juhradiald.- Start-limit hit (
start request repeated too quickly): the daemon crashed five times in a minute and systemd backed off. Clear it and retry: - No device / permission errors in the log: this is really a detection problem, go back to Device detection.
To see the real error directly, stop the service and run the binary in the foreground:
Menu position and visibility¶
Problem: the menu opens in the top-left corner of the screen¶
Cause. The daemon could not read the cursor position from your compositor, so the overlay falls back to the origin. On GNOME this is almost always the cursor-helper Shell extension not being loaded yet (Wayland requires a session restart to activate a newly installed extension).
Fix (GNOME).
gnome-extensions enable juhradial-cursor@dev.juhlabs.com
gnome-extensions info juhradial-cursor@dev.juhlabs.com # State should read ACTIVE
If it is installed but not ACTIVE, log out and back in (or restart the session). On other compositors, a top-left menu means cursor detection failed for a different reason: see Compositor-Support for the per-compositor cursor source (KWin script on KDE, IPC on Hyprland, XWayland on Sway/COSMIC).
Problem: the menu lands near the cursor but drifts further off the more you move from the top-left, especially at non-100% display scale¶
Cause. Coordinate-space mismatch under fractional scaling. The daemon reads the cursor in logical pixels, while the overlay (forced onto XWayland, where Qt6 high-DPI scaling is on) places windows in point space (physical pixels divided by the device pixel ratio). Feeding a logical coordinate straight into the overlay overshoots in proportion to distance from the monitor's top-left corner.
Fix. This is handled in current builds by dividing the cursor coordinate by the cursor screen's devicePixelRatio (with dpr = 1 as the identity case). If you see the drift, you are on an older build: update to the latest release. Confirm your scale with your display settings; the symptom is strongest at 125 percent, 150 percent, and similar.
Problem: the menu opens on the wrong monitor in a multi-display setup¶
Cause. Same coordinate-space root as above. If the cursor coordinate is misscaled, the point can land inside a neighbouring monitor's rectangle. It can also happen when the compositor reports cursor position in a different origin than the overlay expects.
Fix. Update to the current release (the scaling fix above). If it persists, capture the reported cursor position from journalctl --user -u juhradialmx-daemon -f while triggering the menu and open an issue with that output plus your monitor layout and per-display scale.
Problem: the overlay is positioned correctly but hidden behind other windows (Hyprland)¶
Cause. Without window rules, Hyprland tiles or stacks the overlay like a normal window.
Fix. Add the overlay rules (the installer does this automatically on Hyprland). In hyprland.conf or a sourced rules file:
windowrulev2 = float, title:^(JuhRadial MX)$
windowrulev2 = noblur, title:^(JuhRadial MX)$
windowrulev2 = noborder, title:^(JuhRadial MX)$
windowrulev2 = noshadow, title:^(JuhRadial MX)$
windowrulev2 = pin, title:^(JuhRadial MX)$
windowrulev2 = noanim, title:^(JuhRadial MX)$
Then hyprctl reload. See Compositor-Support for other compositors.
Problem: the menu never appears on niri¶
Cause. niri exposes no cursor IPC and breaks XWayland popup placement, which is the positioning path every other compositor uses. The XWayland move() call has nothing to anchor to, so the overlay cannot place itself.
Fix. niri needs a wlr-layer-shell surface via gtk4-layer-shell (a declared dependency) instead of XWayland positioning. Make sure the package is installed:
| Family | Package |
|---|---|
| Fedora | gtk4-layer-shell |
| Arch | gtk4-layer-shell |
| Debian / Ubuntu | libgtk4-layer-shell0 |
| openSUSE | gtk4-layer-shell (may be absent, see openSUSE note) |
Also run xwayland-satellite so the rest of the XWayland pipeline functions. See Compositor-Support for the full niri setup.
Buttons and thumb-wheel actions do nothing¶
Problem: a remapped button or thumb-wheel action (volume, zoom, copy, horizontal scroll) fires nothing¶
Cause. Two separate requirements, and either one missing produces silence:
- Injection helper. Keyboard-shortcut and thumb-wheel actions are injected through the kernel
uinputdevice viaydotool, because XWayland-style injection cannot drive native Wayland windows.ydotoolneeds its background daemon,ydotoold, running. - uinput access. Both
ydotooldand the daemon's own virtual input device must be able to open/dev/uinput, which stock distros ship asroot:root 0600.
Fix.
Start with the helper:
# Is ydotoold present and running?
command -v ydotoold
systemctl --user status ydotoold
# If installed but not running, enable it:
systemctl --user enable --now ydotoold
Then fix uinput permissions. The installer ships a uaccess rule for /dev/uinput (60-ydotool-uinput.rules), loads the uinput module, and ensures you are in the input group. Reproduce that manually if needed:
# 1. Make sure the uinput module is loaded (and loads at boot):
sudo modprobe uinput
echo uinput | sudo tee /etc/modules-load.d/juhradial-uinput.conf
# 2. Install the uinput access rule and reload:
sudo install -Dm644 packaging/udev/60-ydotool-uinput.rules /etc/udev/rules.d/60-ydotool-uinput.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
# 3. Confirm the node is accessible to you:
ls -l /dev/uinput
# 4. Be in the input group (log out/in after first time):
id -nG | grep input
Note
If ydotoold is missing entirely, install ydotool for your distro (dnf install ydotool, pacman -S ydotool, apt install ydotool, zypper install ydotool). The installer prints ydotoold not found: shortcut/thumb-wheel actions may not work on Wayland when it cannot find it.
Problem: only some buttons respond, others do nothing¶
Cause. Only the gesture button and the haptic button are diverted by default. Back, forward, middle, and shift-wheel are not diverted out of the box, so reassigning them in the settings UI has no effect until the daemon diverts them and routes them through its action handler. Diverts also use a volatile flag, so they are lost on device hotplug.
Fix. Update to a build where the button you want is included in the divert set, and re-apply config after a reconnect (ReloadConfig, or just trigger the daemon's reconnect path by re-plugging). If your assignment still does nothing after a reload, the CID for that button is not yet diverted: note which physical button in a GitHub issue. See Features for which buttons are remappable.
Haptics and battery¶
Problem: no haptic feedback, and battery/DPI/Easy-Switch fields are empty¶
Cause. Haptics, battery level, DPI, scroll-ratchet state, and Easy-Switch host all come from HID++ feature calls, which only work on a supported Logitech MX device (MX Master 4, MX Master 3S, MX Master 3). When the daemon falls back to generic mode (any non-HID++ mouse via evdev), only the radial menu and button remapping are available. There is no HID++ channel to query, so those panels stay blank and the actuator never fires.
Fix.
- Confirm you are on a supported device and that HID++ is reachable:
- Make sure
hidrawaccess works (HID++ travels over thehidrawnode, not evdev). This is the same permission story as Device detection: be in theinputgroup and have the udev rules installed. - If you are intentionally using a non-Logitech mouse, this is expected: generic mode does not provide haptics or battery. The radial menu and remapping still work. See Features for the per-mode capability matrix.
Note
Battery and Easy-Switch host update live over HID++. If they were populated and then froze, the device likely roamed to another host (Easy-Switch) or the divert state was lost on hotplug; a reconnect re-runs feature discovery.
Still stuck¶
- Re-run the installer to pull the latest fixes:
- Capture a verbose run and the service logs:
- Open an issue at https://github.com/JuhLabs/juhradial-mx/issues with your distro, compositor (and display scale), the device and connection type (USB receiver vs Bluetooth), and that log.
Related pages: Installation · Configuration · Compositor-Support · Features · FAQ · Architecture · Home