Zackriya-Solutions/meetily · warning · anyhow::Error
Recording is already paused
Error message
Recording is already paused
What it means
pause_recording was called while is_paused is already true - a double-pause. The guard makes repeated pause fail rather than silently restarting the pause timer, which would otherwise corrupt total_pause_duration accounting.
Source
Thrown at frontend/src-tauri/src/audio/recording_state.rs:182
// Clear pause tracking when stopping
*self.pause_start.lock().unwrap() = None;
// CRITICAL: Clear audio sender to close the pipeline channel
// This ensures the pipeline loop exits properly after processing all chunks
*self.audio_sender.lock().unwrap() = None;
// CRITICAL: Clear device references to release microphone/speaker
// Without this, Arc<AudioDevice> references persist and keep the mic active
*self.microphone_device.lock().unwrap() = None;
*self.system_device.lock().unwrap() = None;
*self.disconnected_device.lock().unwrap() = None;
log::info!("Recording stopped, device references cleared");
}
pub fn pause_recording(&self) -> Result<()> {
if !self.is_recording() {
return Err(anyhow::anyhow!("Cannot pause when not recording"));
}
if self.is_paused() {
return Err(anyhow::anyhow!("Recording is already paused"));
}
self.is_paused.store(true, Ordering::SeqCst);
*self.pause_start.lock().unwrap() = Some(Instant::now());
log::info!("Recording paused");
Ok(())
}
pub fn resume_recording(&self) -> Result<()> {
if !self.is_recording() {
return Err(anyhow::anyhow!("Cannot resume when not recording"));
}
if !self.is_paused() {
return Err(anyhow::anyhow!("Recording is not paused"));
}
// Calculate pause duration and add to total
if let Some(pause_start) = self.pause_start.lock().unwrap().take() {View on GitHub (pinned to 0281737d87)
Solutions
- Make the caller idempotent: treat 'already paused' as success
- Debounce or disable the Pause button once the paused state is confirmed
- Check is_recording_paused before sending the command
Example fix
// before
state.pause_recording()?;
// after - idempotent pause at the call site
match state.pause_recording() {
Ok(()) => {}
Err(e) if e.to_string().contains("already paused") => { /* desired state reached */ }
Err(e) => return Err(e),
} Defensive patterns
Strategy: validation
Validate before calling
// Frontend: only pause when actually unpaused
if ((await invoke<boolean>('is_recording')) && !(await invoke<boolean>('is_recording_paused'))) {
await invoke('pause_recording');
} Try / catch
Treat 'Recording is already paused' as success (the desired state is already reached); only surface other errors.
Prevention
- Debounce the pause/resume toggle button
- Use a single toggle control driven by is_recording_paused rather than separate buttons
- Do not retry a pause that already returned success
When it happens
Trigger: Double-click on the Pause button; a keyboard shortcut and a UI button both firing; retry of a pause command that already succeeded but whose result was not observed.
Common situations: Missing debounce on UI buttons; event replay in tests; race between an automatic pause (device reconnect) and a user pause.
Related errors
- Recording is not paused
- Cannot pause when not recording
- Cannot resume when not recording
- Recording not active
- No audio streams could be created
AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16).
Data as JSON: /api/errors/d231cd09be5e7c70.
Report an issue: GitHub.