{"record":{"id":"f2a2080e33851653","repo":"SubtitleEdit/subtitleedit","slug":"crispasr-omnivoice-did-not-report-healthy-within","errorCode":null,"errorMessage":"crispasr (omnivoice) did not report healthy within {5|30} minutes. Last output: {lastOutput}{LaunchCmdSuffix}","messagePattern":"crispasr \\(omnivoice\\) did not report healthy within (.+?) minutes\\. Last output: (.+?)(.+?)","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs","lineNumber":696,"sourceCode":"                    _serverLaunchCommand = null;\n                    _serverModelKey = null;\n                    _serverVoicePath = null;\n                    _serverRefText = null;\n                    throw new InvalidOperationException(\n                        $\"crispasr (omnivoice) 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 (omnivoice) did not report healthy within {(hasLocalModel ? 5 : 30)} 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":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceCrispAsr.cs#L678-L714","documentation":"TimeoutException thrown when the crispasr omnivoice server stays alive but never responds to /health within the deadline (5 minutes for a locally-staged model, 30 minutes if first-run auto-download is needed). StopServerInternal is called before throwing. This is the omnivoice analogue of error 245, with shorter deadlines because omnivoice models are smaller (~1-1.6 GB vs ~10-20 GB for MOSS-TTS).","triggerScenarios":"The startup while-loop exhausts the deadline without ProbeHealthAsync returning true. The server process is still running but the /health endpoint never went green — typically because model loading or first-run download took longer than the configured window.","commonSituations":"First-run auto-download of the ~1.6 GB F16 model on a very slow or throttled connection; the model sits on a network drive with high latency; CPU-only loading on a machine under heavy load; Hugging Face rate-limiting during --auto-download; the crispasr build's /health endpoint has a different path or semantics than expected by ProbeHealthAsync.","solutions":["Check 'Last output' — if it shows download progress, pre-download the model GGUF and tokenizer manually into Se.CrispAsrFolder/models.","Switch to Q4_K (~1 GB) to reduce both download and load time.","Ensure the models are on local storage (SSD preferred), not a network mount.","Verify the installed crispasr version exposes GET /health (older builds may not).","If the deadline is consistently too short for the hardware, consider increasing it in code (the 5/30 split is hardcoded)."],"exampleFix":"// before — hardcoded 5/30 minute split\nvar deadline = DateTime.UtcNow.AddMinutes(hasLocalModel ? 5 : 30);\n\n// after — configurable for slow hardware\nvar baseMinutes = hasLocalModel ? 5 : 30;\nvar extra = Se.Settings.Video.TextToSpeech.CrispAsrExtraStartupMinutes;\nvar deadline = DateTime.UtcNow.AddMinutes(baseMinutes + extra);","handlingStrategy":"retry","validationCode":"// Check if models are staged to predict load time\nvar hasLocalModel = OmniVoiceCrispAsr.AreModelsInstalled(modelKey);\nif (!hasLocalModel)\n    Se.WriteToolsLog(\"First-run download will take up to 30 min for ~1.6 GB.\");","typeGuard":"null","tryCatchPattern":"catch (TimeoutException ex) when (ex.Message.Contains(\"did not report healthy\"))\n{\n    // Server may still be loading. Retry once, or pre-download models.\n    if (attempt == 0 && hasLocalModel) { await Task.Delay(TimeSpan.FromMinutes(1), ct); goto retry; }\n    throw;\n}","preventionTips":["Pre-download models so the 5-minute deadline applies instead of 30.","Place models on a local SSD.","Monitor network throughput during first-run download."],"tags":["timeout","startup","tts","omnivoice","crispasr","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}