{"record":{"id":"87bb2edd853992bb","repo":"Zackriya-Solutions/meetily","slug":"recording-is-not-paused","errorCode":null,"errorMessage":"Recording is not paused","messagePattern":"Recording is not paused","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"frontend/src-tauri/src/audio/recording_state.rs","lineNumber":196,"sourceCode":"        if !self.is_recording() {\n            return Err(anyhow::anyhow!(\"Cannot pause when not recording\"));\n        }\n        if self.is_paused() {\n            return Err(anyhow::anyhow!(\"Recording is already paused\"));\n        }\n\n        self.is_paused.store(true, Ordering::SeqCst);\n        *self.pause_start.lock().unwrap() = Some(Instant::now());\n        log::info!(\"Recording paused\");\n        Ok(())\n    }\n\n    pub fn resume_recording(&self) -> Result<()> {\n        if !self.is_recording() {\n            return Err(anyhow::anyhow!(\"Cannot resume when not recording\"));\n        }\n        if !self.is_paused() {\n            return Err(anyhow::anyhow!(\"Recording is not paused\"));\n        }\n\n        // Calculate pause duration and add to total\n        if let Some(pause_start) = self.pause_start.lock().unwrap().take() {\n            let pause_duration = pause_start.elapsed();\n            *self.total_pause_duration.lock().unwrap() += pause_duration;\n            log::info!(\"Recording resumed after pause of {:.2}s\", pause_duration.as_secs_f64());\n        }\n\n        self.is_paused.store(false, Ordering::SeqCst);\n        Ok(())\n    }\n\n    pub fn is_recording(&self) -> bool {\n        self.is_recording.load(Ordering::SeqCst)\n    }\n\n    pub fn is_paused(&self) -> bool {","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/0281737d87d26352fb0adc78c8c0975f691b23d1/frontend/src-tauri/src/audio/recording_state.rs#L178-L214","documentation":"resume_recording was called when is_paused is false - the session is either actively recording or fully stopped-and-not-paused. The guard prevents a spurious resume from corrupting pause-duration accounting (pause_start would be None).","triggerScenarios":"Double Resume click; Resume raced with an earlier resume that already succeeded; a single toggle button sending resume when the state already flipped.","commonSituations":"Rapid toggling of a combined pause/resume button; duplicated event delivery; scripts replaying resume commands.","solutions":["Use one toggle button driven by the canonical paused state (is_recording_paused command)","Treat 'not paused' resume as idempotent success at the caller","Check paused state before sending resume"],"exampleFix":"// before\nstate.resume_recording()?;\n\n// after - idempotent resume at the call site\nmatch state.resume_recording() {\n    Ok(()) => {}\n    Err(e) if e.to_string().contains(\"not paused\") => { /* desired state reached */ }\n    Err(e) => return Err(e),\n}","handlingStrategy":"validation","validationCode":"// Frontend: only resume when actually paused\nif (await invoke<boolean>('is_recording_paused')) {\n  await invoke('resume_recording');\n}","typeGuard":null,"tryCatchPattern":"Treat 'Recording is not paused' as success (target state already active); surface only genuine failures.","preventionTips":["Drive a single pause/resume toggle from is_recording_paused","Debounce rapid toggling","Avoid replaying duplicate resume commands in scripts/tests"],"tags":["state-machine","recording","invalid-transition","idempotency"],"backgroundTag":"invalid-state-transition","analyzedSha":"0281737d87d26352fb0adc78c8c0975f691b23d1","analyzedAt":"2026-08-16T20:57:52.567Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}