cjpais/Handy · error · anyhow::Error

Silero VAD error: {e}

Error message

Silero VAD error: {e}

What it means

Wraps an error from the Silero ONNX inference call (engine.compute(frame)) during per-frame voice activity detection. The frame length is validated first, so this error means the ONNX session itself failed to execute — typically a corrupted model, a runtime/provider failure, or the LSTM state getting into a bad state after an I/O or session error. It surfaces mid-recording, one 512-sample frame at a time.

Source

Thrown at src-tauri/src/audio_toolkit/vad/silero.rs:44

                .map_err(|e| anyhow::anyhow!("Failed to create VAD: {e}"))?,
            threshold,
        })
    }
}

impl VoiceActivityDetector for SileroVad {
    fn push_frame<'a>(&'a mut self, frame: &'a [f32]) -> Result<VadFrame<'a>> {
        if frame.len() != SILERO_FRAME_SAMPLES {
            anyhow::bail!(
                "expected {SILERO_FRAME_SAMPLES} samples, got {}",
                frame.len()
            );
        }

        let result = self
            .engine
            .compute(frame)
            .map_err(|e| anyhow::anyhow!("Silero VAD error: {e}"))?;

        if result.prob > self.threshold {
            Ok(VadFrame::Speech(frame))
        } else {
            Ok(VadFrame::Noise)
        }
    }

    fn frame_samples(&self) -> usize {
        SILERO_FRAME_SAMPLES
    }

    fn reset(&mut self) {
        // Clear the Silero LSTM hidden/cell state so a new session doesn't
        // inherit recurrent context from the previous recording.
        self.engine.reset();
    }
}

View on GitHub (pinned to c6fa60da2f)

Solutions

  1. Re-download silero_vad_v4.onnx and restart the app — a compute failure almost always traces to a damaged model file.
  2. If it recurs, pin/reinstall the onnxruntime version used by the vad-rs dependency (check Cargo.lock for version drift).
  3. Check system memory and disk health; ONNX execution allocates arenas that can fail under pressure.
  4. Call reset() on the VAD between recording sessions (the code does this) to avoid carrying bad recurrent state forward.

Example fix

// before
let frame = vad.push_frame(samples)?;

// after — treat a VAD compute failure as session-poisoned: reset once, then surface
match vad.push_frame(samples) {
    Ok(frame) => frame,
    Err(e) => {
        warn!("VAD compute failed ({e}); resetting session state");
        vad.reset();
        return Err(e);
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

let frame = match vad.push_frame(chunk) {
    Ok(f) => f,
    Err(e) => {
        // session may be poisoned: reset state, drop this recording
        vad.reset();
        return Err(anyhow::anyhow!("VAD compute failed; session reset: {e}"));
    }
};

Prevention

When it happens

Trigger: Calling SileroVad::push_frame() when the ONNX runtime session errors during compute: model file corrupted on disk, ONNX runtime version/provider mismatch, or engine state invalidated after a previous partial failure.

Common situations: Disk corruption or a truncated silero_vad_v4.onnx that loaded but fails on inference; an ONNX runtime upgraded to an incompatible version; the model resource swapped/modified while the app is running; rare provider-level failures under memory pressure.

Related errors


AI-assisted analysis of cjpais/Handy@c6fa60da2f (2026-08-17). Data as JSON: /api/errors/419854a3dca8d677. Report an issue: GitHub.