SubtitleEdit/subtitleedit · error · InvalidOperationException

crispasr (moss-tts) exited during startup (code {exitCode}).

Error message

crispasr (moss-tts) exited during startup (code {exitCode}). Output: {tail}{LaunchCmdSuffix}

What it means

InvalidOperationException thrown inside the EnsureServerRunningAsync startup-health loop when process.HasExited becomes true before the server responds to /health. The exit code and the last 2000 characters of the server's combined stdout/stderr log are captured and included in the message, along with the full launch command.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/MossTtsCrispAsr.cs:747

            // First-run auto-download (backbone + codec is up to ~20.5 GB) needs a generous
            // timeout; the 8B backbone also takes a while to load from disk.
            var deadline = DateTime.UtcNow.AddMinutes(hasLocalModel ? 10 : 60);
            while (DateTime.UtcNow < deadline)
            {
                ct.ThrowIfCancellationRequested();
                if (process.HasExited)
                {
                    var tail = SnapshotServerLog();
                    var exitCode = process.ExitCode;
                    var exitedLaunchCommand = _serverLaunchCommand;
                    _serverProcess = null;
                    _serverPort = 0;
                    _serverLaunchCommand = null;
                    _serverModelKey = null;
                    _serverVoicePath = null;
                    _serverRefText = null;
                    _serverLanguageArg = null;
                    throw new InvalidOperationException(
                        $"crispasr (moss-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 (moss-tts) did not report healthy within {(hasLocalModel ? 10 : 60)} minutes. Last output: {lastOutput}"
                + LaunchCmdSuffix(timeoutLaunchCommand));
        }
        finally

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Read the 'Output:' section of the exception — it contains the server's stderr which names the exact failure (e.g., 'gguf: invalid magic', 'CUDA error: no kernel image').
  2. If the model file is corrupt, delete it from Se.CrispAsrFolder/models and re-download via the TTS download dialog (the ExpectedFileSizes guard may miss byte-correct corruption).
  3. Check the 'Launch command' suffix and manually run it in a terminal to reproduce and get the full error outside SE.
  4. Update GPU drivers or switch to a CPU/Vulkan build of crispasr if the error is CUDA/Metal related.
  5. Verify the reference voice WAV still exists at the path in the launch command.

Example fix

// before — the process exits silently during polling
if (process.HasExited)
{
    throw new InvalidOperationException(
        $"crispasr (moss-tts) exited during startup (code {exitCode}). Output: {tail}");
}

// after — also surface whether the exit was a known loader/OOM code
var hint = NativeExitCodeHelper.Format("MOSS-TTS (CrispASR)", exitCode, GetSetFolder());
throw new InvalidOperationException(
    $"crispasr (moss-tts) exited during startup (code {exitCode}). {hint} Output: {tail}");
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate model files before server launch
if (!MossTtsCrispAsr.AreModelsInstalled(modelKey))
{
    await ShowDownloadDialog("MOSS-TTS models are incomplete.");
    return;
}

Type guard

null

Try / catch

catch (InvalidOperationException ex) when (ex.Message.Contains("exited during startup"))
{
    // The exit code and server log tail are in the message.
    // Parse them to decide: re-download models, update drivers, or report.
    var tail = ExtractServerLog(ex.Message);
    if (tail.Contains("invalid magic") || tail.Contains("gguf"))
        await OfferModelRedownload();
    else
        throw;
}

Prevention

When it happens

Trigger: The crispasr process starts (Process.Start succeeds) but then exits within the startup polling window. Detected on the next loop iteration when process.HasExited is true. The server log tail reveals the cause: a corrupted/truncated GGUF model file, a missing codec companion, a CUDA/Metal init failure, a port conflict, or an invalid --voice path.

Common situations: A partially-downloaded model file (the ExpectedFileSizes check should catch truncation, but a corrupt-but-correct-size file slips through); GPU drivers missing or incompatible with the crispasr build; the --voice WAV was deleted between server-key computation and launch; a stale port was reused (FindFreeLoopbackPort has a TOCTOU window); the user's system locale causes a model-path parsing failure inside crispasr.

Related errors


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