tonhowtf/omniget · warning · anyhow::Error
ja esta gravando
Error message
ja esta gravando
What it means
start() refuses to begin a new dictation session when REC already holds an active Recording. The guard checks the shared mutex-protected slot and returns this Portuguese message ('already recording') so a second overlapping ffmpeg capture is never spawned. It is an intentional state-machine guard, not a bug.
Solutions
- Call stop() to finish the current recording before calling start() again.
- Debounce/disable the start trigger in the UI while a recording is active (check the phase or expose an is_recording getter).
- If the session is stuck (e.g. ffmpeg hung), kill the ffmpeg child process and clear REC, then retry start().
Example fix
// before
let _ = dictation::start(progress).await?;
// after
if !is_recording() {
dictation::start(progress).await?;
} else {
// already recording: ignore or surface a UI hint
} Defensive patterns
Strategy: validation
Validate before calling
// Rust (caller side)
if is_recording() {
return; // skip start(), already recording
}
dictation::start(progress).await?; Try / catch
match dictation::start(progress).await {
Err(e) if e.to_string().contains("ja esta gravando") => { /* already recording: no-op */ }
other => other?,
} Prevention
- Track recording state in the UI and disable the start trigger while active.
- Always pair start() with a stop(), including on error/cancel paths.
- Expose an is_recording/phase getter and check it before start().
When it happens
Trigger: Calling dictation::start() while a previous start() succeeded and stop() has not yet been called (or is still awaiting).
Common situations: User presses the dictation hotkey twice; frontend double-clicks the mic button without disabling it; a previous stop() failed leaving the recording session stuck in REC.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/f9b0ff7d0f94e304.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/tools/dictation.rs:237
} else {
vec![
"-f".into(),
"pulse".into(),
"-i".into(),
if dev.is_empty() {
"default".into()
} else {
dev.to_string()
},
]
}
}
pub async fn start(progress: super::ProgressFn) -> anyhow::Result<()> {
{
let rec = REC.lock().unwrap_or_else(|e| e.into_inner());
if rec.is_some() {
return Err(anyhow!("ja esta gravando"));
}
}
let ffmpeg = crate::core::dependencies::ensure_ffmpeg().await?;
let opts = options();
let wav = super::temp_dir().join(format!("dictation-{}.wav", uuid::Uuid::new_v4()));
let mut cmd = crate::core::process::command(&ffmpeg);
cmd.args(["-y", "-hide_banner", "-loglevel", "error"]);
cmd.args(input_args(&opts.device));
cmd.args(["-ac", "1", "-ar", "16000", "-c:a", "pcm_s16le"])
.arg(&wav);
cmd.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::piped());
let child = cmd.spawn().map_err(|e| anyhow!("ffmpeg: {}", e))?;
*REC.lock().unwrap_or_else(|e| e.into_inner()) = Some(Recording {
child,
wav,
started: Instant::now(),View on GitHub (pinned to 8600b91f42)