CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

fix: resolve speech-to-text crashes and post-API-key error storm #4738

Merged⚡ AI-generatedXSccantynz wants to mergeclaude/speech-to-text-crashes-lxc2x4mainopened Jun 15, 2026
ccantynzcommented Jun 15, 2026

Originally written by @ccantynz-alt on GitHub.
Imported from https://github.com/ccantynz-alt/voxlen/pull/63


Problem

Users reported: "after installing the API code and going to use the product it just crashes with lots of errors." I spawned three parallel investigation agents (Rust backend, React/TS frontend, and the end-to-end API-key flow) to trace the crashes.

Root cause

API keys are stored only in the OS keychain (for privacy) and were never loaded back into the Rust backend at startup. So on the next launch — or if the user dictated before a 500 ms debounce fired — the backend had no key. The first dictation failed with No API key configured, and the streaming layer then entered an endless reconnect storm, emitting a flood of error/reconnect toasts. That's the literal "lots of errors." Several latent runtime panics in the audio/STT pipeline compounded it.

Fixes

Backend (src-tauri)

  • Keychain hydration at startupload_settings_from_disk now reads sttApiKey / grammarApiKey / voxlenApiKey back from the OS keychain so engines have the keys before the first hotkey. New keyring::read_secret() degrades gracefully when there's no keychain backend (headless Linux).
  • Reconnect storm cap — streaming now gives up after 5 consecutive unhealthy sessions with one clear error instead of spamming reconnect toasts on a bad/missing key.
  • Resample out-of-bounds panic — clamp idx_floor in resample() and simple_resample(); upsampling from a low-rate device (8 kHz telephony / Bluetooth HFP) indexed past the buffer end and panicked.
  • Divide-by-zero panic — guard the chunk-duration divisor against sample_rate/channels == 0 (misreporting / virtual devices).
  • Zero-size chunk loop — reject input devices reporting rate/channels == 0 up front (was a CPU-spin / apparent freeze).
  • UTF-8 truncation panic — truncate device names on a char boundary (String::truncate panicked mid-codepoint on localized names).

Frontend (src)

  • UsageMeter render crash — validate the /api/me payload shape before reading plan/features; a malformed HTTP 200 threw during render and crashed the app right after connecting a key.
  • Unverified token — warn instead of silently treating an unverified token as fully connected when verification can't reach the network.

Testing

  • cargo check clean; new Rust regression tests for resample upsampling and UTF-8 device-name truncation pass.
  • tsc --noEmit clean; all 178 frontend tests pass.

Not yet addressed (follow-ups identified by the agents)

  • Keychain → localStorage fallback means the backend won't find keys written to localStorage on systems with no Secret Service (BUG 6).
  • Provider/key resolution blanks out a working direct key when any Voxlen key is present (BUG 5).

https://claude.ai/code/session_016YZd5wbQ9H1tmr1DZT4MpF


Generated by Claude Code

ccantynzcommented Jun 15, 2026

Originally written by @vercel[bot] on GitHub.


The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
voxlen Ready Ready Preview, Comment Jun 15, 2026 9:18am

Cross-repo impact

See what breaks downstream if this PR merges.

Analyze →
⮌ Merged

This pull request was merged into main.

c comment · e edit title · m merge · a approve · r request changes · ? shortcuts