{"record":{"id":"b88ceb856b04dda3","repo":"microsoft/aspire","slug":"the-tunnel-id-tunnelid-is-invalid-a-valid-tunnel-id-must","errorCode":null,"errorMessage":"The tunnel ID '{tunnelId}' is invalid. A valid tunnel ID must:\n- start and end with a letter or number\n- consist of lowercase letters, numbers, and hyphens\n- be 1-58 characters long\n","messagePattern":"The tunnel ID '(.+?)' is invalid\\. A valid tunnel ID must:\n- start and end with a letter or number\n- consist of lowercase letters, numbers, and hyphens\n- be 1-58 characters long\n","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs","lineNumber":64,"sourceCode":"    /// </code>\n    /// </example>\n    [AspireExportIgnore(Reason = \"Use the dedicated polyglot overload instead.\")]\n    public static IResourceBuilder<DevTunnelResource> AddDevTunnel(\n        this IDistributedApplicationBuilder builder,\n        [ResourceName] string name,\n        string? tunnelId = null,\n        DevTunnelOptions? options = null)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentNullException.ThrowIfNull(name);\n\n        var appHostId = builder.Configuration[\"AppHost:Sha256\"]?[..8];\n        tunnelId ??= $\"{name}-{appHostId}\".ToLowerInvariant();\n\n        // Validate the TunnelId format [a-z0-9][a-z0-9-]{1,58}[a-z0-9]\n        if (!TunnelIdRegex().IsMatch(tunnelId))\n        {\n            throw new ArgumentException($\"\"\"\n                The tunnel ID '{tunnelId}' is invalid. A valid tunnel ID must:\n                - start and end with a letter or number\n                - consist of lowercase letters, numbers, and hyphens\n                - be 1-58 characters long\n                \"\"\", nameof(tunnelId));\n        }\n\n        options ??= new DevTunnelOptions();\n        options.Labels ??= [];\n        options.Labels.Add($\"aspire_{name}-{appHostId}\");\n        options.Description ??= $\"Dev tunnel for '{name}' in Aspire AppHost '{builder.Environment.ApplicationName}'\";\n\n        if (!TryValidateLabels(options.Labels, out var errorMessage))\n        {\n            throw new ArgumentException(errorMessage, nameof(options));\n        }\n\n        // Add services","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs#L46-L82","documentation":"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.","triggerScenarios":"Calling AddDevTunnel/AddDevTunnelForPolyglot with an explicit tunnelId containing uppercase letters, spaces, underscores, leading/trailing hyphens, or >58 characters.","commonSituations":"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.","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"],"exampleFix":"// before\nbuilder.AddDevTunnel(\"my_Tunnel\"); // underscore + uppercase invalid\n// after\nbuilder.AddDevTunnel(\"my-tunnel\");","handlingStrategy":"validation","validationCode":"static string NormalizeTunnelId(string name) =>\n    new string(name.ToLowerInvariant().Select(c => char.IsAsciiLetterOrDigit(c) ? c : '-').ToArray()).Trim('-') is { Length: > 0 } s\n        ? (s.Length <= 58 ? s : s[..58]).TrimEnd('-')\n        : \"tunnel\";","typeGuard":"static bool IsValidTunnelId(string? id) =>\n    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));","tryCatchPattern":"try { builder.AddDevTunnel(tunnelId); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"tunnel ID\"))\n{ logger.LogError(ex, \"Invalid tunnel id '{Id}'\", tunnelId); throw; }","preventionTips":["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"],"tags":["devtunnels","validation","identifier"],"backgroundTag":"invalid-identifier-format","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}