{"record":{"id":"3d03ac92e09d0e63","repo":"SubtitleEdit/subtitleedit","slug":"crispasr-f5-tts-did-not-report-healthy-within","errorCode":null,"errorMessage":"crispasr (f5-tts) did not report healthy within {(hasLocalTalker ? 5 : 20)} minutes. Last output: {lastOutput}{LaunchCmdSuffix}","messagePattern":"crispasr \\(f5-tts\\) did not report healthy within (.+?) minutes\\. Last output: (.+?)(.+?)","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/TextToSpeech/Engines/F5TtsCrispAsr.cs","lineNumber":651,"sourceCode":"                    _serverLaunchCommand = null;\n                    _serverModelKey = null;\n                    _serverVoicePath = null;\n                    _serverRefText = null;\n                    throw new InvalidOperationException(\n                        $\"crispasr (f5-tts) exited during startup (code {exitCode}). Output: {tail}\"\n                        + LaunchCmdSuffix(exitedLaunchCommand));\n                }\n                if (await ProbeHealthAsync(port, TimeSpan.FromSeconds(2), ct))\n                {\n                    return;\n                }\n                await Task.Delay(TimeSpan.FromSeconds(1), ct);\n            }\n\n            var lastOutput = SnapshotServerLog();\n            var timeoutLaunchCommand = _serverLaunchCommand;\n            StopServerInternal();\n            throw new TimeoutException(\n                $\"crispasr (f5-tts) did not report healthy within {(hasLocalTalker ? 5 : 20)} minutes. Last output: {lastOutput}\"\n                + LaunchCmdSuffix(timeoutLaunchCommand));\n        }\n        finally\n        {\n            ServerLock.Release();\n        }\n    }\n\n    private static string SnapshotServerLog()\n    {\n        lock (_serverLog)\n        {\n            var s = _serverLog.ToString().TrimEnd();\n            return s.Length > 2000 ? s[^2000..] : s;\n        }\n    }\n","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/F5TtsCrispAsr.cs#L633-L669","documentation":"Thrown as a TimeoutException when the f5-tts crispasr server starts and stays alive but never answers `/health` within the deadline — 5 minutes if a local talker GGUF is present, 20 minutes otherwise (to allow the ~953 MB first-run auto-download). The server process is stopped and the last 2000 chars of its log are attached.","triggerScenarios":"The model download is slow/stalled on a poor network so the server never finishes loading; the server binds but `/health` hangs (deadlock in the backend); a host firewall blocks the loopback `127.0.0.1:port` health GET; the process is alive but pegged at 100% CPU initializing while the probe times out.","commonSituations":"Slow or proxy-filtered corporate network blocking the model CDN; a CrispASR version whose `/health` route changed; concurrent runs saturating the GPU so init never completes; large model on an underpowered machine.","solutions":["Check the `Last output:` tail — a still-downloading or still-loading server prints progress lines.","If on first run, pre-stage the talker GGUF locally (place it at GetTalkerPath path) so the 5-minute deadline applies instead of 20.","Ensure no firewall/VPN blocks loopback traffic to `127.0.0.1`.","Close other GPU-heavy processes so the server can finish loading within the window.","If the server is genuinely slow to init on your hardware, increase the deadline constant only after confirming the server eventually goes healthy when run manually."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before Speak, sanity-check the model is present so the short 5-min deadline applies\nif (!engine.HasLocalTalker(modelKey))\n{\n    WarnUser(\"First run downloads ~953 MB and may need the full 20-min window on a slow link.\");\n}","typeGuard":null,"tryCatchPattern":"try { await f5Engine.Speak(...); }\ncatch (TimeoutException ex) when (ex.Message.Contains(\"did not report healthy\"))\n{\n    // Often a slow first-run download. Retry once after the user confirms the network/disk is free.\n    if (await ConfirmRetry(\"Server did not become healthy in time. Retry?\"))\n        await f5Engine.Speak(...);\n}","preventionTips":["Pre-download the talker GGUF so the 5-minute deadline applies.","Keep loopback `127.0.0.1` traffic unblocked by firewall/VPN.","Free GPU/CPU before a long TTS job so init completes in time.","Pre-warm the engine with a tiny test utterance before batch runs."],"tags":["f5-tts","crispasr","health-check","timeout","server","tts"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}