cjpais/Handy · error · anyhow::Error
Transcription engine panicked
Error message
Transcription engine panicked: {}. The model has been unloaded and will reload on next attempt. What it means
The engine call is wrapped in catch_unwind(AssertUnwindSafe(...)); this error fires when the native engine (GGML or ONNX Runtime code) panicked instead of returning Err. On panic the engine is deliberately not put back (mutex stays unpoisoned), a model-state-changed "unloaded" event is emitted with "Engine panicked: {msg}", and the error promises the model reloads on the next attempt.
Solutions
- Simply retry once — the engine was unloaded and the next transcribe attempt reloads the model
- Read the panic message in the log to identify the native assertion; search the Handy tracker for that message
- Update the app (bundles newer transcribe-cpp/transcribe-rs with panic fixes)
- Switch to a different engine/model to keep working while the panic is investigated
- Report with logs if reproducible — include audio conditions (length, device, sample rate)
Defensive patterns
Strategy: fallback
Validate before calling
// sanitize audio before it reaches native code
let clean: Vec<f32> = audio.iter().map(|s| if s.is_finite() { *s } else { 0.0 }).collect(); Try / catch
match manager.transcribe(audio.clone()) {
Err(e) if e.to_string().starts_with("Transcription engine panicked") => {
// engine was unloaded; a fresh attempt reloads the model — retry exactly once
manager.transcribe(audio)
}
other => other,
} Prevention
- Always retry once after this error — recovery is by design (reload on next attempt)
- Report reproducible panics with the panic message and audio conditions
- Update the app to pick up engine panic fixes
- Switch engines to keep working while a reproducible panic is investigated
When it happens
Trigger: Any panic inside the matched engine arm: native assertions in transcribe-cpp/transcribe-rs (index out of bounds, unwrap on None), audio containing NaN/inf samples driving a panic in DSP code, or FFI-level crashes surfaced as Rust panics.
Common situations: Buggy engine version for a newly added arch; pathological audio (silence, clipping, corrupt float samples); edge-case sample rates; bugs fixed in later library updates.
Related errors
- English translations must exist
- failed to create cancel item
- failed to create menu
- failed to create model item
- failed to create model submenu
AI-assisted analysis of cjpais/Handy@ba10ce1943 (2026-08-17).
Data as JSON: /api/errors/2a1efe602e3f5eab.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/managers/transcription.rs:1470
{
let mut current_model = self
.current_model_id
.lock()
.unwrap_or_else(|e| e.into_inner());
*current_model = None;
}
let _ = self.app_handle.emit(
"model-state-changed",
ModelStateEvent {
event_type: "unloaded".to_string(),
model_id: None,
model_name: None,
error: Some(format!("Engine panicked: {}", panic_msg)),
},
);
return Err(anyhow::anyhow!(
"Transcription engine panicked: {}. The model has been unloaded and will reload on next attempt.",
panic_msg
));
}
};
let output_language = with_model_detected_language(
resolve_output_language_evidence(
&settings,
applied_language_hint.as_deref(),
&model_languages,
output_was_translated,
),
model_detected_language,
);
debug!("Output language evidence: {:?}", output_language);
(text, output_language, model_languages)View on GitHub (pinned to ba10ce1943)