SubtitleEdit/subtitleedit · error · TimeoutException
crispasr (qwen3-tts) did not report healthy within {hasLocal
Error message
crispasr (qwen3-tts) did not report healthy within {hasLocalTalker && hasLocalCodec ? 5 : 30} minutes. Last output: {lastOutput}{LaunchCmdSuffix} What it means
TimeoutException thrown when crispasr stays alive but never answers /health within the deadline. The deadline is conditional: 5 minutes when both talker and codec GGUFs are already staged locally, 30 minutes when --auto-download must fetch them (~2 GB talker + ~986 MB codec) on first run. The server is stopped and the last log plus launch command are appended.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCrispAsr.cs:1039
_serverProcess = null;
_serverPort = 0;
_serverModelKey = null;
_serverLaunchCommand = null;
throw new InvalidOperationException(
$"crispasr (qwen3-tts) 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 (qwen3-tts) did not report healthy within {(hasLocalTalker && hasLocalCodec ? 5 : 30)} 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
- Pre-stage the talker and codec GGUFs locally so the 5-minute (not 30-minute) deadline applies and no network download is needed.
- Check Last output — a server printing download progress is just slow; a silent log suggests a route/port mismatch.
- Confirm the probe route in ProbeHealthAsync matches this crispasr build's health endpoint.
- If on a slow link, run the first synthesis once outside the app (or pre-download the cache) so subsequent starts hit the short deadline.
Defensive patterns
Strategy: retry
Validate before calling
// Pre-stage models locally so the short (5 min) deadline applies.
var hasLocalTalker = IsValidLocalModelFile(GetTalkerPath(modelKey), GetTalkerFileName(modelKey));
var hasLocalCodec = IsValidLocalModelFile(GetCodecPath(), CodecFileName);
if (!hasLocalTalker || !hasLocalCodec)
await PreDownloadCrispAsrModelsAsync(modelKey); Try / catch
try { await EnsureServerRunningAsync(modelKey, ct); }
catch (TimeoutException ex)
{ Se.LogError(ex); /* offer retry after pre-staging models */ throw; } Prevention
- Pre-stage the talker and codec GGUFs to avoid the 30-minute first-run window.
- Keep the health-probe route in sync with the crispasr build.
- Confirm network/proxy allows the auto-download if models aren't local.
When it happens
Trigger: First-run download over a slow/unreliable link exceeds 30 min; the server is alive but /health was renamed so the probe always fails; GPU init hangs; the model is on a slow network mount and mmap-loads for minutes; the auto-download is blocked by a proxy and the server waits indefinitely.
Common situations: Offline or metered-network first run; a newer crispasr build that changed the health route; a zombie server holding the port; very large model on integrated graphics.
Related errors
- crispasr (chatterbox) did not report healthy within 15 minut
- crispasr (cosyvoice3-tts) did not report healthy within {(al
- crispasr (moss-tts) did not report healthy within {10|60} mi
- crispasr (omnivoice) did not report healthy within {5|30} mi
- qwen3-tts-server did not report healthy within 120s. Last ou
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/c5008eddfd9fa485.
Report an issue: GitHub.