SubtitleEdit/subtitleedit · error · TimeoutException

crispasr (indextts) did not report healthy within {5|15} min

Error message

crispasr (indextts) did not report healthy within {5|15} minutes. Last output: {lastOutput}{LaunchCmdSuffix}

What it means

TimeoutException from IndexTtsCrispAsr.EnsureServerRunningAsync when the indextts server stays alive but never answers `/health` within the deadline — 5 minutes if BOTH local talker and codec GGUFs are present, 15 minutes otherwise (to allow ~870 MB auto-download). The server is stopped and the last 2000 chars of its log plus launch command are attached.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/IndexTtsCrispAsr.cs:631

                    _serverPort = 0;
                    _serverLaunchCommand = null;
                    _serverVoicePath = null;
                    _serverModelKey = null;
                    throw new InvalidOperationException(
                        $"crispasr (indextts) exited during startup (code {exitCode}). Output: {tail}"
                        + LaunchCmdSuffix(exitedLaunchCommand));
                }
                if (await ProbeHealthAsync(port, TimeSpan.FromSeconds(2), ct))
                {
                    return;
                }
                await Task.Delay(TimeSpan.FromSeconds(1), ct);
            }

            var lastOutput = SnapshotServerLog();
            var timeoutLaunchCommand = _serverLaunchCommand;
            StopServerInternal();
            throw new TimeoutException(
                $"crispasr (indextts) did not report healthy within {(hasLocalTalker && hasLocalCodec ? 5 : 15)} minutes. Last output: {lastOutput}"
                + LaunchCmdSuffix(timeoutLaunchCommand));
        }
        finally
        {
            ServerLock.Release();
        }
    }

    private static string SnapshotServerLog()
    {
        lock (_serverLog)
        {
            var s = _serverLog.ToString().TrimEnd();
            return s.Length > 2000 ? s[^2000..] : s;
        }
    }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Inspect `Last output:` for download/loading progress lines.
  2. Pre-stage both talker and codec GGUFs locally so the 5-minute deadline applies.
  3. Ensure loopback `127.0.0.1` traffic is not firewalled.
  4. Free GPU/CPU resources so the server can finish init.
  5. Run the launch command manually to see how long init truly takes on your machine.
Defensive patterns

Strategy: retry

Validate before calling

// Tell users the first-run cost up front
if (!engine.HasLocalTalker(modelKey) || !engine.HasLocalCodec())
    WarnUser("First run downloads ~870 MB; keep the network stable.");

Try / catch

try { await indexEngine.Speak(...); }
catch (TimeoutException ex) when (ex.Message.Contains("did not report healthy"))
{
    if (await ConfirmRetry()) await indexEngine.Speak(...);
}

Prevention

When it happens

Trigger: Model auto-download stalled on a slow/blocked network; the server binds but `/health` deadlocks; loopback firewall blocks the health GET; GPU saturated so init never finishes within the window.

Common situations: Proxy-filtered corporate network blocking the model CDN; CrispASR version whose `/health` route changed; concurrent GPU workload; underpowered hardware loading a large quant.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/1aaa97e4abae7ac7. Report an issue: GitHub.