microsoft/aspire · error · ArgumentException

The label ' ' is invalid. A valid label must: - consist of…

Error message

The label '{label}' is invalid. A valid label must:
- consist of letters, numbers, underscores, hyphens, or equals signs
- be 1-50 characters long

What it means

AddDevTunnel validates every label in options.Labels (labels must be 1-50 chars of letters, digits, underscores, hyphens, or equals signs) via TryValidateLabels; on failure it throws ArgumentException with the multi-line message, attributing it to the options parameter. Note Aspire itself adds an `aspire_{name}-{appHostId}` label, so an invalid resource name can also trigger this.

Solutions

  1. Sanitize each label: letters, numbers, underscore, hyphen, equals only, max 50 chars
  2. Remove or replace offending labels before calling AddDevTunnel
  3. If the auto-added aspire_ label is the problem, shorten/normalize the resource `name` passed to AddDevTunnel

Example fix

// before
options.Labels = ["team:platform", "env.production Very Long Label Over Fifty CharactersXXXXXXXXXXXXXXXX"];
builder.AddDevTunnel("api", options); // throws
// after
options.Labels = ["team=platform", "env=prod"];
builder.AddDevTunnel("api", options);
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidLabel(string label) =>
    label.Length is >= 1 and <= 50 && label.All(c => char.IsLetterOrDigit(c) || c is '_' or '-' or '=');
if (options.Labels?.Any(l => !IsValidLabel(l)) == true)
    throw new InvalidOperationException("One or more dev tunnel labels are invalid");

Type guard

static bool IsValidLabel(string? label) =>
    !string.IsNullOrEmpty(label) && label.Length <= 50 && label.All(c => char.IsLetterOrDigit(c) || c is '_' or '-' or '=');

Try / catch

try { builder.AddDevTunnel(name, options); }
catch (ArgumentException ex) when (ex.Message.Contains("label"))
{ logger.LogError(ex, "Invalid dev tunnel labels"); throw; }

Prevention

When it happens

Trigger: Calling AddDevTunnel with options.Labels containing spaces, periods, characters outside [A-Za-z0-9_- =], empty strings, or labels longer than 50 characters — or with a resource `name` that produces an invalid auto-added aspire_* label.

Common situations: Using dots in labels (common convention, e.g. 'env.prod'); long labels exceeding 50 chars; labels copied from other tagging systems with slashes or colons.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs:79

        // Validate the TunnelId format [a-z0-9][a-z0-9-]{1,58}[a-z0-9]
        if (!TunnelIdRegex().IsMatch(tunnelId))
        {
            throw new ArgumentException($"""
                The tunnel ID '{tunnelId}' is invalid. A valid tunnel ID must:
                - start and end with a letter or number
                - consist of lowercase letters, numbers, and hyphens
                - be 1-58 characters long
                """, nameof(tunnelId));
        }

        options ??= new DevTunnelOptions();
        options.Labels ??= [];
        options.Labels.Add($"aspire_{name}-{appHostId}");
        options.Description ??= $"Dev tunnel for '{name}' in Aspire AppHost '{builder.Environment.ApplicationName}'";

        if (!TryValidateLabels(options.Labels, out var errorMessage))
        {
            throw new ArgumentException(errorMessage, nameof(options));
        }

        // Add services
        builder.Services.TryAddSingleton<DevTunnelLoginManager>();
        builder.Services.TryAddSingleton<LoggedOutNotificationManager>();
        builder.Services.TryAddSingleton<IDevTunnelClient, DevTunnelCliClient>();

        var workingDirectory = builder.AppHostDirectory;
        var tunnelResource = new DevTunnelResource(name, tunnelId, DevTunnelCli.GetCliPath(builder.Configuration), workingDirectory, options);

        // Health check
        var healtCheckKey = $"{name}-check";
        builder.Services.AddHealthChecks().Add(new HealthCheckRegistration(
            healtCheckKey,
            services => new DevTunnelHealthCheck(
                services.GetRequiredService<IDevTunnelClient>(),
                services.GetRequiredService<LoggedOutNotificationManager>(),
                tunnelResource,

View on GitHub (pinned to 25830f84bd)