SubtitleEdit/subtitleedit · error · FileNotFoundException
OmniVoice TTS voice cloning requires a transcript file at {r
Error message
OmniVoice TTS voice cloning requires a transcript file at {refTextPath}. Re-import the voice to provide its transcript. What it means
FileNotFoundException thrown when a cloned voice (omniVoice.FilePath points to an existing WAV) is selected but the sibling .txt transcript file (same basename, .txt extension) does not exist. omnivoice-tts requires --ref-text whenever --ref-wav is set, so SE fails loudly rather than silently producing the default speaker voice.
Source
Thrown at src/ui/Features/Video/TextToSpeech/Engines/OmniVoiceTtsCpp.cs:296
// auto-detect, not "language not found".
if (language != null && !string.IsNullOrEmpty(language.Code))
{
psi.ArgumentList.Add("--lang");
psi.ArgumentList.Add(language.Code);
}
// Voice cloning: omnivoice-tts requires both --ref-wav and --ref-text.
// Pair each voices/<name>.wav with a sibling <name>.txt holding the transcript.
// The transcript is captured at import time; if it has been deleted out from under
// us we fail loudly so the user knows custom voice cloning isn't happening, rather
// than silently producing the default speaker.
var usingReference = !string.IsNullOrEmpty(omniVoice.FilePath) && File.Exists(omniVoice.FilePath);
if (usingReference)
{
var refTextPath = Path.ChangeExtension(omniVoice.FilePath, ".txt");
if (!File.Exists(refTextPath))
{
throw new FileNotFoundException(
$"OmniVoice TTS voice cloning requires a transcript file at {refTextPath}. "
+ "Re-import the voice to provide its transcript.",
refTextPath);
}
psi.ArgumentList.Add("--ref-wav");
psi.ArgumentList.Add(omniVoice.FilePath);
psi.ArgumentList.Add("--ref-text");
psi.ArgumentList.Add(refTextPath);
}
// Voice-design keywords (--instruct) only shape the voice when there is no reference
// audio - with --ref-wav omnivoice-tts takes the voice from the clone and ignores them.
if (!usingReference)
{
var instruction = (Se.Settings.Video.TextToSpeech.OmniVoiceTtsCppInstruction ?? string.Empty).Trim();
if (!string.IsNullOrEmpty(instruction))
{View on GitHub (pinned to 17a9f07487)
Solutions
- Re-import the voice via the Import Voice dialog and provide the transcript text — it writes the .txt sidecar automatically.
- Manually create the .txt file next to the voice WAV with the spoken transcription of the reference audio.
- If the transcript is unknown, use OmniVoiceCrispAsr.TryWriteRefTextSidecar(voiceWavPath, transcript) to write it after import.
- Alternatively, select the 'Default' voice (no FilePath) which does not require a transcript.
Example fix
// before — throws if the sidecar was deleted
var refTextPath = Path.ChangeExtension(omniVoice.FilePath, ".txt");
if (!File.Exists(refTextPath))
throw new FileNotFoundException("...requires a transcript file at " + refTextPath);
// after — fall back to the default voice with a warning if transcript is missing
var refTextPath = Path.ChangeExtension(omniVoice.FilePath, ".txt");
if (usingReference && !File.Exists(refTextPath))
{
Se.WriteToolsLog($"Transcript missing for {omniVoice.FilePath}; falling back to default voice.");
usingReference = false;
} Defensive patterns
Strategy: validation
Validate before calling
// Before synthesis, check for the transcript sidecar
if (!string.IsNullOrEmpty(omniVoice.FilePath) && File.Exists(omniVoice.FilePath))
{
var refTextPath = Path.ChangeExtension(omniVoice.FilePath, ".txt");
if (!File.Exists(refTextPath))
{
await PromptForTranscript(omniVoice.FilePath);
return;
}
} Type guard
null
Try / catch
catch (FileNotFoundException ex) when (ex.Message.Contains("transcript file"))
{
var path = ex.FileName; // the missing .txt path
await PromptForTranscript(Path.ChangeExtension(path, ".wav"));
// After providing transcript, retry
} Prevention
- Always provide a transcript when importing a voice (ImportVoice(fileName, transcript)).
- Do not delete .txt sidecars next to voice WAVs.
- Use the 'Default' voice if no transcript is available.
When it happens
Trigger: usingReference is true (omniVoice.FilePath is non-empty and the WAV exists), but Path.ChangeExtension(omniVoice.FilePath, ".txt") does not exist. This happens when the transcript sidecar was manually deleted, or the voice was copied/imported without its transcript.
Common situations: The user deleted the .txt file next to a voice WAV to save space; the voice was imported via a path that didn't carry the transcript (ImportVoice with a null transcript and no source sidecar); a file-sync tool excluded .txt files but synced .wav files; the voice was seeded from another engine's folder but the sidecar filter rejected the text as an unusable attribution blurb.
Related errors
- CrispASR executable not found. Install CrispASR via Video →
- omnivoice-tts executable not found.
- OmniVoice TTS models not found in {GetSetModelsFolder()}. Do
- CrispASR executable not found. Install CrispASR via Video →
- OmniVoice (CrispASR) — the crispasr server crashed during sy
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/c4113de403fe4b13.
Report an issue: GitHub.