SubtitleEdit/subtitleedit · error · InvalidOperationException

yt-dlp is not installed

Error message

yt-dlp is not installed

What it means

Thrown by DownloadVideo when the yt-dlp binary file does not exist at GetFullFileName() before launching it. This is a precondition check: the caller must run DownloadYtDlp (which downloads and verifies the binary) before attempting a video download. The check uses File.Exists so a missing, moved, or never-downloaded binary all trigger it.

Source

Thrown at src/ui/Logic/Download/YtDlpDownloadService.cs:219

            {
                File.Delete(filePath);
            }
        }
        catch
        {
            // Best-effort cleanup; a leftover bad file is re-checked on next download.
        }
    }

    private static readonly Regex PercentageRegex = new(@"(?<pct>\d+(?:\.\d+)?)\s*%", RegexOptions.Compiled);

    public async Task DownloadVideo(string url, string outputPath, bool downloadAllSubtitles, IProgress<float>? progress, CancellationToken cancellationToken, IProgress<YtDlpDownloadStage>? stageProgress = null)
    {
        cancellationToken.ThrowIfCancellationRequested();

        if (!File.Exists(GetFullFileName()))
        {
            throw new InvalidOperationException("yt-dlp is not installed");
        }

        var args = new List<string>
        {
            "--newline",       // emit one progress line per update, never carriage-return rewriting
            "--no-mtime",      // don't carry remote mtime to the local file
            "--no-playlist",   // single video only — playlist URLs would download many files
            "-o", outputPath,
        };

        if (downloadAllSubtitles)
        {
            // Ride along with the video download: yt-dlp writes every available
            // human-uploaded subtitle track as a sibling file using the same
            // <stem>.<lang>.<ext> naming so the caller can find them by globbing.
            args.Add("--write-subs");
            args.Add("--sub-langs");
            args.Add("all");

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Call DownloadYtDlp first (it downloads + checksum-verifies the binary) and only call DownloadVideo once that succeeds.
  2. Check File.Exists(YtDlpDownloadService.GetFullFileName()) in the UI and trigger the download dialog when missing.
  3. Ensure Se.DataFolder is created and writable so the downloaded binary actually lands there.
  4. If an antivirus removed the binary, allow-list Se.DataFolder and re-run DownloadYtDlp.

Example fix

// before
await _ytDlp.DownloadVideo(url, outPath, false, progress, ct);

// after
if (!File.Exists(YtDlpDownloadService.GetFullFileName()))
{
    await _ytDlp.DownloadYtDlp(progress, ct); // install first
}
await _ytDlp.DownloadVideo(url, outPath, false, progress, ct);
Defensive patterns

Strategy: validation

Validate before calling

if (!File.Exists(YtDlpDownloadService.GetFullFileName()))
    await svc.DownloadYtDlp(progress, ct);

Type guard

static bool IsYtDlpInstalled() => File.Exists(YtDlpDownloadService.GetFullFileName());

Try / catch

try { await svc.DownloadVideo(url, outPath, false, progress, ct); }
catch (InvalidOperationException ex) when (ex.Message == "yt-dlp is not installed")
{ await svc.DownloadYtDlp(progress, ct); await svc.DownloadVideo(url, outPath, false, progress, ct); }

Prevention

When it happens

Trigger: Calling DownloadVideo before DownloadYtDlp has been run on this machine, or after the yt-dlp binary was deleted from Se.DataFolder (e.g. user cleared the folder, an antivirus quarantined it).

Common situations: First-time use where the auto-download step was skipped/failed, or a portable install moved between machines without carrying the DataFolder.

Related errors


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