{"record":{"id":"a6281d047b256712","repo":"microsoft/aspire","slug":"the-label-label-is-invalid-a-valid-label-must-consist-of","errorCode":null,"errorMessage":"The label '{label}' is invalid. A valid label must:\n- consist of letters, numbers, underscores, hyphens, or equals signs\n- be 1-50 characters long\n","messagePattern":"The label '(.+?)' is invalid\\. A valid label must:\n- consist of letters, numbers, underscores, hyphens, or equals signs\n- be 1-50 characters long\n","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs","lineNumber":79,"sourceCode":"        // 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\n        builder.Services.TryAddSingleton<DevTunnelLoginManager>();\n        builder.Services.TryAddSingleton<LoggedOutNotificationManager>();\n        builder.Services.TryAddSingleton<IDevTunnelClient, DevTunnelCliClient>();\n\n        var workingDirectory = builder.AppHostDirectory;\n        var tunnelResource = new DevTunnelResource(name, tunnelId, DevTunnelCli.GetCliPath(builder.Configuration), workingDirectory, options);\n\n        // Health check\n        var healtCheckKey = $\"{name}-check\";\n        builder.Services.AddHealthChecks().Add(new HealthCheckRegistration(\n            healtCheckKey,\n            services => new DevTunnelHealthCheck(\n                services.GetRequiredService<IDevTunnelClient>(),\n                services.GetRequiredService<LoggedOutNotificationManager>(),\n                tunnelResource,","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Sanitize each label: letters, numbers, underscore, hyphen, equals only, max 50 chars","Remove or replace offending labels before calling AddDevTunnel","If the auto-added aspire_ label is the problem, shorten/normalize the resource `name` passed to AddDevTunnel"],"exampleFix":"// before\noptions.Labels = [\"team:platform\", \"env.production Very Long Label Over Fifty CharactersXXXXXXXXXXXXXXXX\"];\nbuilder.AddDevTunnel(\"api\", options); // throws\n// after\noptions.Labels = [\"team=platform\", \"env=prod\"];\nbuilder.AddDevTunnel(\"api\", options);","handlingStrategy":"validation","validationCode":"static bool IsValidLabel(string label) =>\n    label.Length is >= 1 and <= 50 && label.All(c => char.IsLetterOrDigit(c) || c is '_' or '-' or '=');\nif (options.Labels?.Any(l => !IsValidLabel(l)) == true)\n    throw new InvalidOperationException(\"One or more dev tunnel labels are invalid\");","typeGuard":"static bool IsValidLabel(string? label) =>\n    !string.IsNullOrEmpty(label) && label.Length <= 50 && label.All(c => char.IsLetterOrDigit(c) || c is '_' or '-' or '=');","tryCatchPattern":"try { builder.AddDevTunnel(name, options); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"label\"))\n{ logger.LogError(ex, \"Invalid dev tunnel labels\"); throw; }","preventionTips":["Replace ':' or '.' separators in labels with '=' or '-'","Keep labels at most 50 characters","Remember the auto-added aspire_{name}-{hash} label must also be valid, so keep the resource name simple"],"tags":["devtunnels","validation","labels"],"backgroundTag":"invalid-argument-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"}