Tyrrrz/YoutubeDownloader · error · InvalidOperationException

No suitable download option found.

Error message

No suitable download option found.

What it means

Thrown by VideoDownloader.GetBestDownloadOptionAsync when preference.TryGetBestOption(options) returns null - none of the resolved stream options satisfy the user's VideoDownloadPreference (container + video-quality preference). The options come from VideoDownloadOption.ResolveAll(manifest, ...) over the stream manifest fetched from YouTube via YoutubeExplode.

Source

Thrown at YoutubeDownloader.Core/Downloading/VideoDownloader.cs:44

        var manifest = await _youtube.Videos.Streams.GetManifestAsync(videoId, cancellationToken);
        return VideoDownloadOption.ResolveAll(manifest, includeLanguageSpecificAudioStreams);
    }

    public async Task<VideoDownloadOption> GetBestDownloadOptionAsync(
        VideoId videoId,
        VideoDownloadPreference preference,
        bool includeLanguageSpecificAudioStreams = true,
        CancellationToken cancellationToken = default
    )
    {
        var options = await GetDownloadOptionsAsync(
            videoId,
            includeLanguageSpecificAudioStreams,
            cancellationToken
        );

        return preference.TryGetBestOption(options)
            ?? throw new InvalidOperationException("No suitable download option found.");
    }

    public async Task DownloadVideoAsync(
        string filePath,
        IVideo video,
        VideoDownloadOption downloadOption,
        bool includeSubtitles = true,
        string? ffmpegPath = null,
        IProgress<Percentage>? progress = null,
        CancellationToken cancellationToken = default
    )
    {
        // Include subtitles in the output container
        var trackInfos = new List<ClosedCaptionTrackInfo>();
        if (includeSubtitles && !downloadOption.Container.IsAudioOnly)
        {
            var manifest = await _youtube.Videos.ClosedCaptions.GetManifestAsync(
                video.Id,

View on GitHub (pinned to bbcff03951)

Solutions

  1. Broaden the VideoDownloadPreference (allow MP4 and WebM, multiple quality tiers) so TryGetBestOption has candidates.
  2. Call GetDownloadOptionsAsync first and choose from the returned list, or iterate progressively relaxed preferences until one yields an option.
  3. Re-fetch the manifest (availability is transient) and verify access - authenticate with cookies for age/login-gated videos before retrying.

Example fix

// before: throws when nothing matches the strict preference
var option = await downloader.GetBestDownloadOptionAsync(videoId, preference, ct);

// after: inspect available options and pick a safe fallback
var options = await downloader.GetDownloadOptionsAsync(videoId, includeLanguageSpecificAudioStreams: true, ct);
var option = preference.TryGetBestOption(options)
    ?? options.FirstOrDefault()
    ?? throw new InvalidOperationException("Video has no downloadable streams.");
Defensive patterns

Strategy: validation

Validate before calling

var options = await downloader.GetDownloadOptionsAsync(
    videoId, includeLanguageSpecificAudioStreams: true, ct);

if (options.Count is 0)
{
    // tell the user the video has no downloadable streams (private/removed/live/restricted)
}

var chosen = preference.TryGetBestOption(options);
if (chosen is null)
{
    // surface the actually-available containers/qualities and relax the preference
}

Try / catch

VideoDownloadOption option;
try
{
    option = await downloader.GetBestDownloadOptionAsync(videoId, preference, cancellationToken: ct);
}
catch (InvalidOperationException ex) when (ex.Message == "No suitable download option found.")
{
    var fallback = await downloader.GetDownloadOptionsAsync(videoId, cancellationToken: ct);
    option = fallback.FirstOrDefault() ?? throw;
}

Prevention

When it happens

Trigger: The manifest contains no combination matching the preference: preference demands MP4 but only WebM/adaptive streams exist; the requested quality tier isn't published; the video is audio-only, a live stream, age-restricted, membership/premium-only, region-blocked, or removed; or includeLanguageSpecificAudioStreams=false filtered out the only audio track needed to pair with a video stream.

Common situations: A restrictive container/quality preference; YouTube rotating codecs so the preferred container disappears for a video; missing cookies for login/age-gated content; language-specific audio excluded leaving nothing muxable; access-restricted or transiently unavailable streams.


AI-assisted analysis of Tyrrrz/YoutubeDownloader@bbcff03951 (2026-08-13). Data as JSON: /api/errors/4a8ca1365736fee0. Report an issue: GitHub.