SubtitleEdit/subtitleedit · critical · InvalidOperationException
crispasr (qwen3-tts) exited during startup
Error message
crispasr (qwen3-tts) exited during startup (code {exitCode}). Output: {tail}{LaunchCmdSuffix} What it means
InvalidOperationException thrown during the crispasr startup health-wait when process.HasExited becomes true before /health succeeds. The message includes the raw exit code, the captured server log tail, and the launch command suffix so the user can reproduce the failing invocation manually.
Solutions
- Read the appended Output tail — crispasr prints its fatal reason (e.g. 'failed to load talker', 'unknown backend').
- Run the printed Launch command manually in a terminal to see the full stderr.
- Confirm the talker and codec GGUFs are complete downloads or let --auto-download re-fetch.
- Match the --backend value to a backend that exists in this crispasr build.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: confirm model files and voice dir exist.
if (!Directory.Exists(GetSetVoicesFolder()))
throw new DirectoryNotFoundException("--voice-dir target missing.");
if (hasLocalTalker && !IsValidLocalModelFile(talker, GetTalkerFileName(modelKey)))
throw new FileNotFoundException("Talker model invalid", talker); Try / catch
try { await EnsureServerRunningAsync(modelKey, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("exited during startup"))
{ await ShowServerStartupHelpAsync(ex.Message); throw; } Prevention
- Pre-stage complete talker/codec GGUFs or confirm network access for --auto-download.
- Match --backend to a backend compiled into this crispasr build.
- Run the printed launch command manually to capture full stderr.
When it happens
Trigger: Missing shared libraries abort crispasr before main; the talker/codec GGUF specified via -m is missing or corrupt; the --backend name doesn't match a compiled backend; --voice-dir points at a non-existent folder and crispasr aborts; GPU/driver incompatibility.
Common situations: First run before models are staged locally (the code falls back to --auto-download, which can still fail offline); a backend was compiled out of this crispasr build; a partial model download; driver/runtime mismatch.
Related errors
- crispasr (moss-tts) did not report healthy within
- crispasr (moss-tts) exited during startup
- crispasr (omnivoice) did not report healthy within
- crispasr (omnivoice) exited during startup
- crispasr (qwen3-tts) did not report healthy within
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/636f424fd1dc5c33.
Report an issue: GitHub.
Appendix: source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCrispAsr.cs:1025
_serverPort = port;
_serverModelKey = modelKey;
HookProcessExitOnce();
// First-run auto-download (~2 GB talker + ~986 MB codec) needs a generous timeout.
var deadline = DateTime.UtcNow.AddMinutes(hasLocalTalker && hasLocalCodec ? 5 : 30);
while (DateTime.UtcNow < deadline)
{
ct.ThrowIfCancellationRequested();
if (process.HasExited)
{
var tail = SnapshotServerLog();
var exitCode = process.ExitCode;
var exitedLaunchCommand = _serverLaunchCommand;
_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));
}
finallyView on GitHub (pinned to 17a9f07487)