mgth/LittleBigMouse · warning
!! $*
Error message
${Y}!! $*${N} What it means
This is not a thrown exception: the string "${Y}!! $*${N}" is the body of the warn() helper defined in run-lbm.sh. It prints a yellow '!!' warning line when the terminal is a TTY (colors are pre-expanded into the Y/N variables), and plain text otherwise. Any operational warning from the setup script — e.g. failure to stop a running instance — is emitted through it.
Solutions
- Read the text following '!!' in the script output — warn() is informational; the script usually continues unless a later step exits.
- If the warning is about stopping instances, run pgrep -af 'littlebigmouse|dotnet' to find survivors and kill them manually.
- Re-run the script in a TTY to see colorized output and full context of which step warned.
- Inspect the call sites of warn in run-lbm.sh for the specific step that triggered the line and address its underlying condition.
Example fix
# diagnostic pgrep -af 'littlebigmouse|dotnet.*LittleBigMouse' || echo "no instance running" # manual stop if warn() reported a survivor pkill -f 'LittleBigMouse.*\.dll'; pkill -x littlebigmouse
Defensive patterns
Strategy: try-catch
Validate before calling
# before running the script, ensure no stale instances block it pgrep -af 'littlebigmouse|dotnet.*LittleBigMouse' && pkill -f 'LittleBigMouse.*\.dll' || true
Try / catch
out=$(./run-lbm.sh 2>&1) || { echo "$out" | grep '!!'; exit 1; }
echo "$out" | grep '!!' || true # warnings are informational; only exit status matters Prevention
- Run the script in a TTY so warnings are colorized and easy to spot.
- Treat warn() lines as informational; gate success on the script's exit code instead.
- Stop running instances manually (pkill -f LittleBigMouse) before rerunning after a failed setup.
When it happens
Trigger: Executing run-lbm.sh on any code path that calls warn "..."; the message only appears as a log line. The color codes interpolate when stdout is a TTY, and the arguments to warn fill $*.
Common situations: pkill failing to match a running instance (already stopped or unexpected process name); leftover socket/lock files found; non-fatal environment checks failing during setup.
AI-assisted analysis of mgth/LittleBigMouse@7a42f01d47 (2026-09-16).
Data as JSON: /api/errors/87414ef33f1f8db0.
Report an issue: GitHub.
Appendix: source
Thrown at run-lbm.sh:70
# Release -> target/release, Debug -> target/debug (matches the UI's config, which
# is what LittleBigMouseClientService.FindHookPath prefers).
if [[ "$CONFIG" == "Release" ]]; then RUST_PROFILE_DIR="release"; else RUST_PROFILE_DIR="debug"; fi
RUST_BIN="$RUST_DIR/target/$RUST_PROFILE_DIR/lbm-hook"
STAGED_HOOK="$BIN_DIR/lbm-hook"
LOG="${TMPDIR:-/tmp}/lbm-ui.log"
# Dev version stamp: v5.4.1 + 12 commits -> 5.4.1.12, so the About window tells
# dev builds apart from releases. Empty (Directory.Build.props version applies)
# when git or the tags are unavailable.
VERSION="$(git -C "$ROOT" describe --tags --long --match 'v*' 2>/dev/null \
| sed -E 's/^v//; s/-([0-9]+)-g[0-9a-f]+$/.\1/')"
# Colours (skipped when not a TTY).
if [[ -t 1 ]]; then C='\033[36m'; D='\033[90m'; Y='\033[33m'; G='\033[32m'; R='\033[31m'; N='\033[0m'
else C=''; D=''; Y=''; G=''; R=''; N=''; fi
step() { echo -e "\n${C}==> $*${N}"; }
note() { echo -e " ${D}$*${N}"; }
warn() { echo -e "${Y}!! $*${N}"; }
# 1. stop running instance(s). The bracketed letter keeps pkill from matching its
# own command line. Three patterns: `dotnet …dll` launches, apphost launches
# (the script prefers the apphost), and a distribution package launched through
# its /usr/bin/littlebigmouse entry point — whose command line carries none of
# the assembly name, so the first two patterns walk straight past it. Miss any
# of them and the old instance survives, the relaunch dies on the
# single-instance lock, and you are left looking at the stale app with an empty
# log. EVIOCGRAB releases on process exit, so this also frees any grabbed mice.
#
# ORDER AND WAITING BOTH MATTER, and for the same reason: the UI relaunches the
# daemon whenever it loses the connection. That contract is only suspended for a
# clean tray Exit (`_quitting`, see "Stop relaunching the daemon the UI is
# quitting"); a signal does not go through QuitAsync, so a SIGTERM'd UI keeps its
# reconnect loop running while it winds down. Kill the daemon while any UI is
# still breathing and it spawns a REPLACEMENT, which survives into the launch
# below still holding the mice — and with a different PID, so it reads as a kill
# that failed rather than a spawn that should not have happened.View on GitHub (pinned to 7a42f01d47)