SubtitleEdit/subtitleedit · error · TimeoutException
kokoro-tts-server did not report healthy within 60s. Last ou
Error message
kokoro-tts-server did not report healthy within 60s. Last output: {lastOutput} What it means
TimeoutException from KokoroTtsCpp.EnsureServerRunningAsync when the kokoro-tts-server starts and stays alive but does not answer `/health` within 60 seconds. The server is stopped and the last 2000 chars of combined stdout/stderr are attached. Kokoro has no large auto-download, so the deadline is a flat 60s — slower hardware or heavy model load can exhaust it.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/KokoroTtsCpp.cs:378
_serverPort = 0;
// An empty tail plus a 0xC00000xx code means the loader killed it before main -
// NativeExitCodeHelper explains those instead of just printing the raw number.
var hint = NativeExitCodeHelper.GetHint(process.ExitCode, "Kokoro TTS", GetSetFolder());
throw new InvalidOperationException(
$"kokoro-tts-server exited during startup (code {NativeExitCodeHelper.Describe(process.ExitCode)})."
+ (hint == null ? string.Empty : " " + hint)
+ $" Output: {tail}");
}
if (await ProbeHealthAsync(port, TimeSpan.FromSeconds(1), ct))
{
return;
}
await Task.Delay(TimeSpan.FromMilliseconds(500), ct);
}
var lastOutput = SnapshotStderr(stderrBuffer);
StopServerInternal();
throw new TimeoutException(
$"kokoro-tts-server did not report healthy within 60s. Last output: {lastOutput}");
}
finally
{
ServerLock.Release();
}
}
private static string SnapshotStderr(StringBuilder buffer)
{
lock (buffer)
{
var s = buffer.ToString().TrimEnd();
return s.Length > 2000 ? s[^2000..] : s;
}
}
private static async Task<bool> ProbeHealthAsync(int port, TimeSpan timeout, CancellationToken ct)View on GitHub (pinned to 17a9f07487)
Solutions
- Inspect `Last output:` for the server's load progress.
- Run the server manually to measure real init time; if it consistently exceeds 60s on your hardware, pre-warm the model.
- Disable AV scanning of the models folder.
- Move models to faster storage (SSD).
- Free CPU/disk contention during startup.
Defensive patterns
Strategy: retry
Validate before calling
// Pre-warm the model so the 60s window is enough on slow disks await kokoroEngine.PreWarmAsync(ct); // touch/mmap the model once
Try / catch
try { await kokoroEngine.Speak(...); }
catch (TimeoutException ex) when (ex.Message.Contains("did not report healthy within 60s"))
{
if (await ConfirmRetry()) await kokoroEngine.Speak(...);
} Prevention
- Pre-warm the engine with a tiny utterance before batch jobs.
- Exclude the models folder from AV on-open scanning.
- Keep models on SSD.
- Free CPU/disk contention during the first startup.
When it happens
Trigger: The server is alive but `/health` is unresponsive (slow model mmap load on a cold disk); loopback firewall blocking the health GET; the server is waiting on a missing dependency and hung (not exited); concurrent disk/CPU contention.
Common situations: First run with a cold OS file cache so model load is slow; antivirus scanning the model on open; slow HDD; heavy background I/O.
Related errors
- crispasr (f5-tts) did not report healthy within {(hasLocalTa
- crispasr (indextts) did not report healthy within {5|15} min
- crispasr (chatterbox) did not report healthy within 15 minut
- crispasr (cosyvoice3-tts) did not report healthy within {(al
- crispasr (f5-tts) exited during startup (code {exitCode}). O
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/dbb99de865ab164c.
Report an issue: GitHub.