microsoft/aspire · error · InvalidOperationException

Channel ' ' does not support CLI downloads.

Error message

Channel '{channelName}' does not support CLI downloads.

What it means

DownloadLatestCliAsync throws InvalidOperationException when the resolved channel exists but its CliDownloadBaseUrl is null or empty, meaning the channel is valid for package resolution but does not host CLI binaries for download.

Solutions

  1. Switch to a channel that supports CLI binary downloads (has CliDownloadBaseUrl).
  2. Obtain the CLI via another distribution path (installer scripts, GitHub releases) instead of this channel.
  3. If this is an internal channel, populate CliDownloadBaseUrl in its packaging metadata.

Example fix

// before
await cliDownloader.DownloadLatestCliAsync("template-only-channel", ct);
// after
await cliDownloader.DownloadLatestCliAsync("stable", ct);   // channel with CliDownloadBaseUrl
Defensive patterns

Strategy: validation

Validate before calling

var channels = await packagingService.GetChannelsAsync(ct);
var channel = channels.FirstOrDefault(c => c.Name.Equals(channelName, StringComparison.OrdinalIgnoreCase));
if (channel is null || string.IsNullOrEmpty(channel.CliDownloadBaseUrl))
{
    throw new InvalidOperationException($"Channel '{channelName}' does not support CLI downloads.");
}

Try / catch

try { await cliDownloader.DownloadLatestCliAsync(channel, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not support CLI downloads")) { // fall back to installer script or another channel
}

Prevention

When it happens

Trigger: Requesting a CLI download from a channel whose packaging metadata lacks CliDownloadBaseUrl — typically feed-only or template-only channels.

Common situations: Using a channel intended only for NuGet package consumption (not binary distribution); local/packaging channels without download URLs configured.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/84746686515e16c3. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Utils/CliDownloader.cs:45

    private const int ArchiveDownloadTimeoutSeconds = 600;
    private const int ChecksumDownloadTimeoutSeconds = 120;

    private static readonly HttpClient s_httpClient = new();

    public async Task<string> DownloadLatestCliAsync(string channelName, CancellationToken cancellationToken)
    {
        // Get the channel information from PackagingService
        var channels = await packagingService.GetChannelsAsync(cancellationToken, channelName);
        var channel = channels.FirstOrDefault(c => c.Name.Equals(channelName, StringComparison.OrdinalIgnoreCase));

        if (channel is null)
        {
            throw new ArgumentException($"Unsupported channel '{channelName}'. Available channels: {string.Join(", ", channels.Select(c => c.Name))}");
        }

        if (string.IsNullOrEmpty(channel.CliDownloadBaseUrl))
        {
            throw new InvalidOperationException($"Channel '{channelName}' does not support CLI downloads.");
        }

        var baseUrl = channel.CliDownloadBaseUrl.TrimEnd('/');

        var (os, arch) = DetectPlatform();
        var runtimeIdentifier = $"{os}-{arch}";
        var extension = os == "win" ? "zip" : "tar.gz";
        var archiveFilename = $"aspire-cli-{runtimeIdentifier}.{extension}";
        var checksumFilename = $"{archiveFilename}.sha512";
        var archiveUrl = $"{baseUrl}/{archiveFilename}";
        var checksumUrl = $"{baseUrl}/{checksumFilename}";

        // Create temp directory for download
        var tempDir = Directory.CreateTempSubdirectory("aspire-cli-download").FullName;

        try
        {
            var archivePath = Path.Combine(tempDir, archiveFilename);

View on GitHub (pinned to 25830f84bd)