SubtitleEdit/subtitleedit · error · InvalidOperationException

Qwen3 TTS (CrispASR) voice cloning requires a reference voic

Error message

Qwen3 TTS (CrispASR) voice cloning requires a reference voice. Import one via the voice settings (you'll be asked for its transcript), then pick it in the voice combo.

What it means

InvalidOperationException thrown when the user selected the voice-clone (Base) model but the chosen Qwen3TtsVoice has no FilePath (no imported reference WAV). The check is done up-front so the user gets an actionable message instead of an opaque HTTP 500 'ref-text not set' from the crispasr server, which resolves the bare voice name against --voice-dir and needs the reference audio.

Source

Thrown at src/ui/Features/Video/TextToSpeech/Engines/Qwen3TtsCrispAsr.cs:750

        string? model,
        CancellationToken cancellationToken)
    {
        if (voice.EngineVoice is not Qwen3TtsVoice qwen3Voice)
        {
            throw new ArgumentException("Voice is not a Qwen3TtsVoice");
        }

        var modelKey = ResolveModelKey(model);

        // Voice clone (Base) needs a reference WAV plus its transcript. The backend resolves the
        // bare voice name against --voice-dir and auto-loads the matching <name>.txt as ref-text;
        // without that transcript it returns "ref-text not set" (HTTP 500). Surface both gaps
        // up-front with an actionable message instead of an opaque server error.
        if (modelKey == ModelKeyClone)
        {
            if (string.IsNullOrEmpty(qwen3Voice.FilePath))
            {
                throw new InvalidOperationException(
                    "Qwen3 TTS (CrispASR) voice cloning requires a reference voice. "
                    + "Import one via the voice settings (you'll be asked for its transcript), "
                    + "then pick it in the voice combo.");
            }

            if (string.IsNullOrWhiteSpace(TryReadUsableTranscript(qwen3Voice.FilePath)))
            {
                throw new InvalidOperationException(
                    $"Qwen3 TTS (CrispASR) voice cloning needs the spoken transcription of '{qwen3Voice.Voice}'. "
                    + "Re-import the voice and enter the exact words spoken in the reference WAV.");
            }
        }

        await EnsureServerRunningAsync(modelKey, cancellationToken);

        var outputFileName = Path.Combine(TtsOutputFolder.Resolve(outputFolder, GetSetFolder), Guid.NewGuid() + ".wav");
        var inputText = text;
        // Share the qwen3-tts.cpp instruction setting so users get the same voice description

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Import a reference voice via the voice settings before selecting the Clone model.
  2. Confirm the imported reference WAV still exists on disk and re-import if it was removed.
  3. Gate the Clone model option in the UI on whether at least one voice with a FilePath exists.
  4. If the voice list shows a clone voice but FilePath is empty, re-run GetSetVoicesFolder seeding.
Defensive patterns

Strategy: validation

Validate before calling

if (modelKey == ModelKeyClone && string.IsNullOrEmpty(qwen3Voice.FilePath))
    throw new InvalidOperationException("Clone model requires an imported reference voice.");

Prevention

When it happens

Trigger: Selecting the 'Clone' model while the voice combo holds only the built-in/default voice with no FilePath; the imported reference WAV was deleted from disk between import and synthesis; the voice was constructed without seeding a FilePath.

Common situations: User picks Clone before importing any reference voice; reference file was cleared by a cleanup tool; migration from an older config that didn't persist FilePath.

Related errors


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