Skip to content

bug(whisper): voice transcription crashes (SIGILL) on CPUs without AVX2/BMI2 #246

Description

@chrisbonilla95

Bug

On CPUs without AVX2/BMI2 (Sandy/Ivy Bridge-era Xeons, some low-power NAS/homelab boxes), the bundled prebuilt whisper-cli crashes with SIGILL / "illegal instruction" (exit 132) on every voice message — the prebuilt emits instructions the CPU lacks (ggml's GGML_BMI2=ON default emits shlx/sarx in ggml_cpu_init, plus AVX2 paths). This hits exactly the "runs on low-spec machines" audience the project targets, and there's no supported way to substitute a compatible binary — even after building one locally, the auto-download machinery owns that path.

How to reproduce

On an older CPU (e.g. Xeon E5-26xx, no AVX2/BMI2): send the bot a Telegram voice message → the transcription subprocess exits 132, transcription silently fails.

Proposed fix (implemented)

Add an optional telegram.whisperBinPath — when set, claudeclaw runs that binary and skips the bundled download; when unset, behaviour is unchanged. Opt-in, minimal, and unblocks affected users immediately (they build/supply a compatible whisper-cli once).

// src/config.ts — TelegramConfig
whisperBinPath?: string;   // absolute path to a self-contained whisper-cli

// src/whisper.ts — the RUN path resolves custom-or-bundled; the DOWNLOAD path
// always targets the bundled location (never clobbers the custom one), and a
// configured-but-missing binary errors clearly instead of re-downloading the
// incompatible prebuilt over it.

Branch (implemented, with tests): https://github.com/chrisbonilla95/claudeclaw/tree/fix/whisper-custom-binary
(diff vs master: master...chrisbonilla95:claudeclaw:fix/whisper-custom-binary)

The branch also handles three non-obvious spots this override touches — worth knowing regardless of direction:

  • The auto-download must never target the custom path (else a missing custom binary re-downloads the incompatible prebuilt onto it).
  • The background warmup is a separate process (src/whisper-warmup.ts) that didn't loadSettings(), so the override (and any configured whisperModel) was ignored there — the branch loads settings in that process too.
  • A custom binary skips bundled shared-lib extraction, so it must be self-contained / statically linked.

Alternatives (if you'd rather fix it built-in)

The config escape-hatch above is the lightweight route; if you'd prefer claudeclaw to handle it automatically instead:

  • CPU-feature detection at warmup → download/select a baseline artifact (needs a baseline build published in releases).
  • Ship a baseline build as the default (portability over peak speed), or offer both.

Happy to open the branch above as a PR, or help with a built-in approach — whichever fits the project best.


Posted by Claude after discussing with @chrisbonilla95

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions