SubtitleEdit/subtitleedit · error · InvalidOperationException

MOSS-TTS (CrispASR) requires a reference voice WAV. Import o

Error message

MOSS-TTS (CrispASR) requires a reference voice WAV. Import one via the voice settings, then pick it in the voice combo. Reference WAV should be mono (3-10 s of clean speech); an adjacent .txt file with the spoken transcription is optional but improves cloning quality.

What it means

InvalidOperationException from MossTtsCrispAsr.Speak when the MossTtsVoice is the correct type but its `FilePath` is null or empty. MOSS-TTS is a cloning engine that bakes the reference WAV into the server at startup via `--voice` (and an optional adjacent `.txt` for ref-text). An empty path is unrecoverable; the message directs the user to import a reference WAV (mono, 3–10 s) and notes the optional transcription `.txt` improves cloning.

Source

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

        GetVoices(language);

    public async Task<TtsResult> Speak(
        string text,
        string outputFolder,
        Voice voice,
        TtsLanguage? language,
        string? region,
        string? model,
        CancellationToken cancellationToken)
    {
        if (voice.EngineVoice is not MossTtsVoice mossVoice)
        {
            throw new ArgumentException("Voice is not a MossTtsVoice");
        }

        if (string.IsNullOrEmpty(mossVoice.FilePath))
        {
            throw new InvalidOperationException(
                "MOSS-TTS (CrispASR) requires a reference voice WAV. "
                + "Import one via the voice settings, then pick it in the voice combo. "
                + "Reference WAV should be mono (3-10 s of clean speech); an adjacent .txt file "
                + "with the spoken transcription is optional but improves cloning quality.");
        }

        var refText = TryReadRefText(mossVoice.FilePath);
        var modelKey = ResolveModelKey(model);
        var languageArg = MossTtsLanguages.ResolveLanguageArg(language);
        await EnsureServerRunningAsync(modelKey, mossVoice.FilePath, refText, languageArg, cancellationToken);

        var outputFileName = Path.Combine(TtsOutputFolder.Resolve(outputFolder, GetSetFolder), Guid.NewGuid() + ".wav");

        var speed = Math.Clamp(Se.Settings.Video.TextToSpeech.MossTtsCrispAsrSpeed, 0.25, 4.0);
        var payload = BuildSpeakPayload(text, speed);

        var body = JsonSerializer.Serialize(payload);
        using var content = new StringContent(body, Encoding.UTF8, "application/json");

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Open voice settings and import a clean 3–10 s mono WAV as the MOSS-TTS reference.
  2. Optionally place a `.txt` with the transcription next to the WAV (TryReadRefText picks it up).
  3. Re-select the voice in the MOSS-TTS combo so the entry is bound to the file.
  4. If the WAV moved, re-import from its new location.

Example fix

// before
var voice = new Voice { EngineVoice = new MossTtsVoice { FilePath = "" } };

// after
var voice = new Voice { EngineVoice = new MossTtsVoice { FilePath = @"C:\Voices\ref.wav" } };
Defensive patterns

Strategy: validation

Validate before calling

if (voice.EngineVoice is MossTtsVoice mv && string.IsNullOrEmpty(mv.FilePath))
{
    PromptImportReferenceWav();
    return;
}

Try / catch

try { await mossEngine.Speak(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("requires a reference voice WAV"))
{
    PromptImportReferenceWav();
}

Prevention

When it happens

Trigger: Selecting a MOSS-TTS voice entry created before a reference WAV was attached; deleting/moving the referenced WAV after import; a settings migration that lost FilePath.

Common situations: User picked the engine before importing a clip; reference file on a detached removable drive; older settings format that didn't persist FilePath.

Related errors


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