microsoft/aspire · error · ArgumentException
The tunnel ID ' ' is invalid. A valid tunnel ID must: -…
Error message
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
What it means
AddDevTunnel validates the generated or supplied tunnel ID against the devtunnel service rules: lowercase letters, numbers, and hyphens, starting/ending alphanumeric, 1-58 chars (regex [a-z0-9][a-z0-9-]{1,58}[a-z0-9]). Invalid IDs throw this ArgumentException before any CLI call.
Solutions
- Provide an explicit tunnelId of lowercase letters, numbers, and hyphens, 1-58 chars, not starting/ending with a hyphen
- Pre-lowercase and normalize (replace '_' with '-') before calling AddDevTunnel
- Shorten the name if the derived `{name}-{appHostId}` exceeds 58 characters
Example fix
// before
builder.AddDevTunnel("my_Tunnel"); // underscore + uppercase invalid
// after
builder.AddDevTunnel("my-tunnel"); Defensive patterns
Strategy: validation
Validate before calling
static string NormalizeTunnelId(string name) =>
new string(name.ToLowerInvariant().Select(c => char.IsAsciiLetterOrDigit(c) ? c : '-').ToArray()).Trim('-') is { Length: > 0 } s
? (s.Length <= 58 ? s : s[..58]).TrimEnd('-')
: "tunnel"; Type guard
static bool IsValidTunnelId(string? id) =>
id is not null && System.Text.RegularExpressions.Regex.IsMatch(id, "^[a-z0-9][a-z0-9-]{0,56}[a-z0-9]$|^[a-z0-9]$", System.Text.RegularExpressions.RegexOptions.None, TimeSpan.FromSeconds(1)); Try / catch
try { builder.AddDevTunnel(tunnelId); }
catch (ArgumentException ex) when (ex.Message.Contains("tunnel ID"))
{ logger.LogError(ex, "Invalid tunnel id '{Id}'", tunnelId); throw; } Prevention
- Lowercase and strip underscores/spaces from names before use
- Keep derived ids under 58 chars including the 8-char hash suffix
- Avoid leading/trailing hyphens
When it happens
Trigger: Calling AddDevTunnel/AddDevTunnelForPolyglot with an explicit tunnelId containing uppercase letters, spaces, underscores, leading/trailing hyphens, or >58 characters.
Common situations: Passing a project name with underscores or mixed case as tunnelId; long resource names exceeding 58 chars even after the 8-char AppHost hash suffix is appended; non-ASCII names.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Cannot tunnel endpoint
- Invalid protocol ' ' specified in port options. Supported…
- {result.ValidationMessage}
- The label ' ' is invalid. A valid label must: - consist of…
- -32602
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/b88ceb856b04dda3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs:64
/// </code>
/// </example>
[AspireExportIgnore(Reason = "Use the dedicated polyglot overload instead.")]
public static IResourceBuilder<DevTunnelResource> AddDevTunnel(
this IDistributedApplicationBuilder builder,
[ResourceName] string name,
string? tunnelId = null,
DevTunnelOptions? options = null)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
var appHostId = builder.Configuration["AppHost:Sha256"]?[..8];
tunnelId ??= $"{name}-{appHostId}".ToLowerInvariant();
// 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 servicesView on GitHub (pinned to 25830f84bd)