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

  1. Read the text following '!!' in the script output — warn() is informational; the script usually continues unless a later step exits.
  2. If the warning is about stopping instances, run pgrep -af 'littlebigmouse|dotnet' to find survivors and kill them manually.
  3. Re-run the script in a TTY to see colorized output and full context of which step warned.
  4. 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

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)