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
- Switch to a channel that supports CLI binary downloads (has CliDownloadBaseUrl).
- Obtain the CLI via another distribution path (installer scripts, GitHub releases) instead of this channel.
- 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
- Check channel.CliDownloadBaseUrl is non-empty before attempting CLI download.
- Use channels documented as supporting binary CLI distribution.
- Provide a fallback install path (installer scripts) for non-download channels.
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
- Unsupported channel ' '. Available channels
- Checksum validation failed. Expected
- Extracted CLI executable not found
- No channel found matching
- Already connected to AppHost backchannel.
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)