{"record":{"id":"514af094fd7a3a94","repo":"microsoft/aspire","slug":"result-validationmessage","errorCode":null,"errorMessage":"{result.ValidationMessage}","messagePattern":"\\{result\\.ValidationMessage\\}","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"critical","filePath":"src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs","lineNumber":138,"sourceCode":"            {\n                var logger = e.Services.GetRequiredService<ResourceLoggerService>().GetLogger(tunnelResource);\n                var eventing = e.Services.GetRequiredService<IDistributedApplicationEventing>();\n                var commandValidator = e.Services.GetRequiredService<IRequiredCommandValidator>();\n                var devTunnelEnvironmentManager = e.Services.GetRequiredService<DevTunnelLoginManager>();\n                var devTunnelClient = e.Services.GetRequiredService<IDevTunnelClient>();\n\n                // Validate the CLI is available and version is supported.\n                // We use manual validation here instead of WithRequiredCommand call because our\n                // OnBeforeResourceStarted handler runs before the global RequiredCommandValidationLifecycleHook runs.\n                var cliAnnotation = new RequiredCommandAnnotation(tunnelResource.Command)\n                {\n                    HelpLink = \"https://learn.microsoft.com/azure/developer/dev-tunnels/get-started#install\",\n                    ValidationCallback = ValidateDevTunnelCliVersionAsync\n                };\n                var result = await commandValidator.ValidateAsync(tunnelResource, cliAnnotation, ct).ConfigureAwait(false);\n                if (!result.IsValid)\n                {\n                    throw new DistributedApplicationException(result.ValidationMessage);\n                }\n\n                // Login to the dev tunnels service if needed\n                logger.LogInformation(\"Ensuring user is logged in to dev tunnel service\");\n                await devTunnelEnvironmentManager.EnsureUserLoggedInAsync(ct).ConfigureAwait(false);\n\n                // Create the dev tunnel\n                string resolvedTunnelId;\n                try\n                {\n                    logger.LogInformation(\"Creating dev tunnel '{TunnelId}'\", tunnelResource.TunnelId);\n                    var tunnelStatus = await devTunnelClient.CreateTunnelAsync(tunnelResource.TunnelId, tunnelResource.Options, logger, ct).ConfigureAwait(false);\n                    // The CLI resolves a bare ID and returns its cluster-qualified ID. Use that ID for\n                    // port operations because bare IDs may not resolve tunnels across clusters.\n                    // See https://github.com/microsoft/aspire/issues/18790.\n                    resolvedTunnelId = tunnelStatus.TunnelId;\n                    logger.LogDebug(\"Dev tunnel '{TunnelId}' created\", tunnelResource.TunnelId);\n                }","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs#L120-L156","documentation":"AddDevTunnel validates the dev tunnel resource (including the local Dev Tunnels CLI version, via ValidateDevTunnelCliVersionAsync) before proceeding to login and tunnel creation. If validation fails, result.ValidationMessage describes the concrete problem and the builder throws a DistributedApplicationException to abort startup rather than creating a broken tunnel. It is a fail-fast guard so misconfigured tunnels or an unusable CLI are surfaced immediately.","triggerScenarios":"Calling AddDevTunnel/AddDevTunnelForPolyglot when commandValidator.ValidateAsync returns IsValid=false for the tunnel resource — typically because the Dev Tunnels CLI is not installed, is missing from PATH, or has an unsupported version detected by the CLI version validation callback.","commonSituations":"Fresh machines or CI agents where the Dev Tunnels CLI (devtunnel) was never installed; an outdated devtunnel version below the minimum supported by the package; CLI installed only for another user/shell so it is not on PATH.","solutions":["Read the thrown ValidationMessage to see the exact validation failure it reports.","Install or update the Dev Tunnels CLI per https://learn.microsoft.com/azure/developer/dev-tunnels/get-started#install and ensure 'devtunnel' resolves on PATH.","Re-run the app host after the CLI fix; validation is re-executed on each start."],"exampleFix":"// before (CLI missing/outdated => validation fails at startup)\nvar tunnel = builder.AddDevTunnel(\"my-tunnel\").WithReference(api);\n// after: install/update devtunnel first, e.g.\n// winget install Microsoft.DevTunnels --version <latest>\n// then verify: devtunnel --version\nvar tunnel = builder.AddDevTunnel(\"my-tunnel\").WithReference(api);","handlingStrategy":"validation","validationCode":"// before starting the app host\nvar psi = new System.Diagnostics.ProcessStartInfo(\"devtunnel\", \"--version\") { RedirectStandardOutput = true };\nusing var p = System.Diagnostics.Process.Start(psi)!;\nvar ver = p.StandardOutput.ReadToEnd();\nif (string.IsNullOrWhiteSpace(ver)) throw new InvalidOperationException(\"Dev Tunnels CLI not installed/on PATH\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install/update the devtunnel CLI as part of machine and CI image setup","Verify 'devtunnel --version' works in the same shell/PATH used by the app host","Pin a minimum CLI version in your team docs and check it in onboarding scripts"],"tags":["devtunnels","cli","validation","startup"],"backgroundTag":"missing-dependency","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"}