{"record":{"id":"ec8bc7d2a0202039","repo":"cjpais/Handy","slug":"timed-out-waiting-for-live-transcription-to-f","errorCode":null,"errorMessage":"Timed out waiting {:?} for live transcription to finalize","messagePattern":"Timed out waiting (.+?) for live transcription to finalize","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/managers/transcription.rs","lineNumber":1129,"sourceCode":"    /// `Ok(None)` means no usable stream was active and the caller may fall back\n    /// to batch transcription. `Err` means finalize itself failed or timed out.\n    /// A timeout may still leave the worker holding the engine, so callers\n    /// should surface it instead of immediately starting a batch fallback.\n    pub fn finalize_stream(&self) -> Result<Option<String>> {\n        let Some(tx) = self.router.take() else {\n            return Ok(None);\n        };\n        let (reply_tx, reply_rx) = mpsc::channel();\n        if tx.send(StreamCmd::Finalize(reply_tx)).is_err() {\n            return Ok(None);\n        }\n        let finalized = match reply_rx.recv_timeout(STREAM_FINALIZE_REPLY_TIMEOUT) {\n            Ok(Some(finalized)) => finalized,\n            Ok(None) => return Ok(None),\n            Err(mpsc::RecvTimeoutError::Disconnected) => return Ok(None),\n            Err(mpsc::RecvTimeoutError::Timeout) => {\n                self.stream_active.store(false, Ordering::Release);\n                return Err(anyhow::anyhow!(\n                    \"Timed out waiting {:?} for live transcription to finalize\",\n                    STREAM_FINALIZE_REPLY_TIMEOUT\n                ));\n            }\n        };\n\n        let settings = get_settings(&self.app_handle);\n        // Streaming models do not receive a decode prompt, so custom words\n        // always go through the shared fuzzy post-correction path.\n        let filtered = post_process_transcription_text(\n            finalized.text,\n            &settings,\n            false,\n            &finalized.output_language,\n            &finalized.supported_languages,\n        );\n\n        self.maybe_unload_immediately(\"streaming transcription\");","sourceCodeStart":1111,"sourceCodeEnd":1147,"githubUrl":"https://github.com/cjpais/Handy/blob/ba10ce1943ef34e93c09494027fc0b9ced2e8a44/src-tauri/src/managers/transcription.rs#L1111-L1147","documentation":"finalize_stream sends StreamCmd::Finalize to the streaming worker and blocks on reply_rx.recv_timeout for STREAM_FINALIZE_REPLY_TIMEOUT (30s). A Timeout means the worker did not reply in time — typically because flushing the accumulated stream and running final inference took longer than 30s. On timeout the code clears stream_active and returns this error; the worker may still hold the engine, so callers must surface the error rather than immediately starting a batch fallback.","triggerScenarios":"User stops a long live-transcription session and the streaming model's finalize inference exceeds 30s: very long buffered audio, CPU starvation (heavy foreground app), GPU hang/stall in the ONNX provider, or the worker thread busy draining a large Feed backlog before the FIFO-ordered Finalize command is even reached.","commonSituations":"Long dictation sessions on slow hardware; system under load (builds, games); GPU driver reset mid-inference; default quantization of the streaming model being too heavy for the machine.","solutions":["Retry the recording — the timed-out worker eventually finishes or exits and the engine state recovers on subsequent loads","Shorten live sessions or check the stream perf logs (logged every STREAM_PERF_LOG_INTERVAL = 5s) to see how far behind the worker is","Switch the accelerator setting (GPU to CPU or back) or use a lighter model if finalize is consistently slow","Rebuild with a larger STREAM_FINALIZE_REPLY_TIMEOUT if long sessions are the norm","Check system logs for GPU driver resets if the timeout correlates with display issues"],"exampleFix":"// before: 30s hard limit\nconst STREAM_FINALIZE_REPLY_TIMEOUT: Duration = Duration::from_secs(30);\n\n// after: allow long sessions to finalize\nconst STREAM_FINALIZE_REPLY_TIMEOUT: Duration = Duration::from_secs(120);","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"match manager.finalize_stream() {\n    Ok(Some(text)) => insert_text(text),\n    Ok(None) => { /* no stream was active: batch-transcribe the buffer */ }\n    Err(e) if e.to_string().contains(\"Timed out waiting\") => {\n        // worker may still hold the engine — surface to the user, do NOT\n        // immediately batch-fallback (per finalize_stream's contract)\n        notify_user_timeout();\n    }\n    Err(e) => notify_user(e),\n}","preventionTips":["End live sessions periodically on slow hardware instead of one very long take","Watch the 5s stream perf logs to detect the worker falling behind before it times out","Pick a quantization/model weight your machine can finalize within 30s","If timeouts correlate with GPU driver resets, run with CPU accelerator"],"tags":["rust","streaming","timeout","finalize","moonshine"],"backgroundTag":"operation-timed-out","analyzedSha":"ba10ce1943ef34e93c09494027fc0b9ced2e8a44","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}