cjpais/Handy · critical · anyhow::Error
Failed to create SileroVad
Error message
Failed to create SileroVad: {} What it means
SileroVad::new failed to load or instantiate the ONNX VAD model at resources/models/silero_vad_v4.onnx. Construction spans reading the file and creating an ONNX runtime session, so failures mean: the file is missing (dev checkout that skipped the documented curl step), the file is corrupt/truncated, or the ONNX runtime cannot initialize (missing dynamic libraries or an incompatible ort build). Recording cannot start without VAD, hence the impact.
Solutions
- Run the documented step: curl -o src-tauri/resources/models/silero_vad_v4.onnx https://blob.handy.computer/silero_vad_v4.onnx
- Verify the file size/hash against the upstream blob and re-download if truncated
- Check that tauri.conf.json bundle.resources includes resources/models so the file ships
- Confirm ONNX runtime dynamic libraries are present/loaded (check the inner error text after 'Failed to create SileroVad:')
Example fix
// before
let silero = SileroVad::new(vad_path, VAD_THRESHOLD)
.map_err(|e| anyhow::anyhow!("Failed to create SileroVad: {}", e))?;
// after — distinguish 'missing resource' from 'broken runtime' with an actionable message
if !vad_path.exists() {
anyhow::bail!(
"VAD model missing at {vad_path:?} — fetch silero_vad_v4.onnx (see AGENTS.md prerequisites)"
);
}
let silero = SileroVad::new(vad_path, VAD_THRESHOLD)
.map_err(|e| anyhow::anyhow!("Failed to create SileroVad: {}", e))?; Defensive patterns
Strategy: validation
Validate before calling
// fail with an actionable message before ONNX runtime involvement
if !vad_path.exists() {
anyhow::bail!(
"VAD model missing at {vad_path:?} — run the AGENTS.md curl step or fix bundling"
);
}
let silero = SileroVad::new(vad_path, VAD_THRESHOLD)?; Try / catch
if let Err(e) = create_audio_recorder(&vad_path, ...) {
if e.to_string().contains("Failed to create SileroVad") {
// resource/packaging problem: check file existence + size before retrying,
// and surface a 'reinstall / refetch resource' message to the user
}
return Err(e);
} Prevention
- Add the silero_vad_v4.onnx fetch to a setup script so fresh clones and CI can't skip it
- Assert the resource exists (and its byte size) in a startup self-test, failing fast with a clear message
- Verify bundle.resources covers resources/models on every packaging change
When it happens
Trigger: Fresh clone built without fetching silero_vad_v4.onnx into src-tauri/resources/models (AGENTS.md prerequisite); resource not bundled because tauri.conf.json's bundle.resources omits it; onnx file truncated by an interrupted curl; ort shared libraries missing on the runtime system.
Common situations: New contributor/CI environment missing the manually-downloaded resource; packaging config drift dropping the models dir from bundles; binary copied to a machine without the required ONNX runtime libs.
Related errors
- Failed to create VAD
- Silero VAD error
- Canary transcription failed
- Cohere transcription failed
- Failed to load canary model
AI-assisted analysis of cjpais/Handy@c89b7bf389 (2026-08-17).
Data as JSON: /api/errors/9cc9d7f9d9c9a446.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/managers/audio.rs:290
/// user's regular selected microphone is missing.
struct MicrophoneResolution {
device: Option<cpal::Device>,
unavailable_selected_microphone: Option<String>,
}
/* ──────────────────────────────────────────────────────────────── */
fn create_audio_recorder(
vad_path: &Path,
app_handle: &tauri::AppHandle,
selected_channel: Option<u16>,
stream_router: Arc<StreamRouter>,
) -> Result<AudioRecorder, anyhow::Error> {
// A single Silero engine covers both the offline and streaming policies (never
// active at once within a recording), so the recorder reconfigures its
// hangover tail per session rather than keeping two ONNX sessions resident.
let silero = SileroVad::new(vad_path, VAD_THRESHOLD)
.map_err(|e| anyhow::anyhow!("Failed to create SileroVad: {}", e))?;
let smoothed_vad = SmoothedVad::new(
Box::new(silero),
VAD_PREFILL_FRAMES,
VAD_OFFLINE_HANGOVER_FRAMES,
VAD_ONSET_FRAMES,
);
// Recorder with VAD, a spectrum-level callback that forwards level updates to
// the frontend, and an audio-frame callback that feeds live streaming via a
// shared `StreamRouter` (captured directly, not via Tauri state — see its docs).
let recorder = AudioRecorder::new()
.map_err(|e| anyhow::anyhow!("Failed to create AudioRecorder: {}", e))?
.with_vad(
Box::new(smoothed_vad),
VAD_OFFLINE_HANGOVER_FRAMES,
VAD_STREAMING_HANGOVER_FRAMES,
)
.with_selected_channel(selected_channel)View on GitHub (pinned to c89b7bf389)