{"record":{"id":"2fa21c0bb0e27025","repo":"SubtitleEdit/subtitleedit","slug":"f5-tts-crispasr-requires-a-reference-voice-wav","errorCode":null,"errorMessage":"F5-TTS (CrispASR) requires a reference voice WAV. Import one via the voice settings, then pick it in the voice combo. Reference WAV should be 24 kHz mono (3-10 s of clean speech) with an adjacent .txt file holding the spoken transcription.","messagePattern":"F5-TTS \\(CrispASR\\) requires a reference voice WAV\\. Import one via the voice settings, then pick it in the voice combo\\. Reference WAV should be 24 kHz mono \\(3-10 s of clean speech\\) with an adjacent \\.txt file holding the spoken transcription\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/TextToSpeech/Engines/F5TtsCrispAsr.cs","lineNumber":368,"sourceCode":"        GetVoices(language);\n\n    public async Task<TtsResult> Speak(\n        string text,\n        string outputFolder,\n        Voice voice,\n        TtsLanguage? language,\n        string? region,\n        string? model,\n        CancellationToken cancellationToken)\n    {\n        if (voice.EngineVoice is not F5TtsVoice f5Voice)\n        {\n            throw new ArgumentException(\"Voice is not an F5TtsVoice\");\n        }\n\n        if (string.IsNullOrEmpty(f5Voice.FilePath))\n        {\n            throw new InvalidOperationException(\n                \"F5-TTS (CrispASR) requires a reference voice WAV. \"\n                + \"Import one via the voice settings, then pick it in the voice combo. \"\n                + \"Reference WAV should be 24 kHz mono (3-10 s of clean speech) with an \"\n                + \"adjacent .txt file holding the spoken transcription.\");\n        }\n\n        var refText = TryReadRefText(f5Voice.FilePath);\n        var modelKey = ResolveModelKey(model);\n        await EnsureServerRunningAsync(modelKey, f5Voice.FilePath, refText, cancellationToken);\n\n        var outputFileName = Path.Combine(TtsOutputFolder.Resolve(outputFolder, GetSetFolder), Guid.NewGuid() + \".wav\");\n\n        var speed = Math.Clamp(Se.Settings.Video.TextToSpeech.F5TtsCrispAsrSpeed, 0.25, 4.0);\n        // Deliberately NO `voice` / `ref_text` field: the server rejects absolute paths outright\n        // (HTTP 400, \"'voice' must not contain … path separators\" — path-traversal guard), so\n        // sending f5Voice.FilePath failed every synthesis. The f5-tts backend reads the reference\n        // from the startup --voice / --ref-text flags (no bare-name resolution), and the server\n        // restarts on (voice, ref-text) change — see EnsureServerRunningAsync. Same bug family as","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/TextToSpeech/Engines/F5TtsCrispAsr.cs#L350-L386","documentation":"InvalidOperationException from F5TtsCrispAsr.Speak: the F5TtsVoice was accepted (type matched) but its FilePath is null/empty. F5-TTS is a voice-cloning engine — it always needs a reference WAV (24 kHz mono, 3–10 s clean speech) plus an adjacent .txt transcription sidecar. Unlike CosyVoice3, this is a hard throw rather than an error result.","triggerScenarios":"Speak proceeds past the type check, then string.IsNullOrEmpty(f5Voice.FilePath) is true; the voice was created without importing a reference WAV, or the FilePath was cleared.","commonSituations":"An F5TtsVoice constructed without an import; the imported WAV file path was reset/lost on settings reload; a cast row selected a default F5 voice that has no reference attached.","solutions":["Import a 24 kHz mono reference WAV (3–10 s clean speech) via the F5-TTS voice settings, then select it in the voice combo.","Place an adjacent .txt file with the spoken transcription next to the WAV so ref-text is auto-read.","Validate FilePath is set before queueing the segment so the run aborts earlier with a clearer message."],"exampleFix":"// before\nvar f5Voice = new F5TtsVoice { Name = \"my clone\" }; // no FilePath\nawait f5TtsEngine.Speak(text, out, new Voice(f5Voice), lang, region, model, ct);\n\n// after\nvar f5Voice = new F5TtsVoice { Name = \"my clone\", FilePath = @\"C:\\voices\\ref.wav\" };\nawait f5TtsEngine.Speak(text, out, new Voice(f5Voice), lang, region, model, ct);","handlingStrategy":"validation","validationCode":"if (voice.EngineVoice is F5TtsVoice f5 && string.IsNullOrEmpty(f5.FilePath)) {\n    Se.WriteToolsLog(\"F5-TTS voice has no reference WAV; prompt the user to import one.\", true);\n    return new TtsResult { Text = text, FileName = string.Empty, Error = true, ErrorMessage = \"Import a 24 kHz mono reference WAV first.\" };\n}","typeGuard":null,"tryCatchPattern":"try { await f5TtsEngine.Speak(text, out, voice, lang, region, model, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"requires a reference voice WAV\", StringComparison.Ordinal))\n{ Se.WriteToolsLog(\"Import a 24 kHz mono reference WAV for this F5-TTS voice, then retry.\", true); }","preventionTips":["Validate F5TtsVoice.FilePath is set before queueing segments.","Always pair the WAV with an adjacent .txt transcription sidecar.","Use 24 kHz mono, 3–10 s clean speech for the reference."],"tags":["tts","f5-tts","crispasr","voice-cloning","missing-reference","configuration"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}