{"record":{"id":"4d1763f3d6459f69","repo":"microsoft/aspire","slug":"failed-to-get-devtunnel-cli-version-output-output-error","errorCode":null,"errorMessage":"Failed to get devtunnel CLI version. Output: '{output}'. Error: '{error}'","messagePattern":"Failed to get devtunnel CLI version\\. Output: '(.+?)'\\. Error: '(.+?)'","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.DevTunnels/DevTunnelCliClient.cs","lineNumber":63,"sourceCode":"                .FirstOrDefault(l => l.StartsWith(prefix, StringComparison.OrdinalIgnoreCase));\n            var versionString = versionLine?.Length > prefix.Length\n                ? versionLine[prefix.Length..].Trim()\n                : output;\n\n            // Trim the commit SHA suffix if present\n            if (versionString.IndexOf('+') is >= 0 and var plusIndex)\n            {\n                versionString = versionString[..plusIndex];\n            }\n\n            if (Version.TryParse(versionString, out var version))\n            {\n                return version;\n            }\n        }\n\n        var error = errorWriter.ToString().Trim();\n        throw new DistributedApplicationException($\"Failed to get devtunnel CLI version. Output: '{output}'. Error: '{error}'\");\n    }\n\n    public async Task<DevTunnelStatus> CreateTunnelAsync(string tunnelId, DevTunnelOptions options, ILogger? logger = default, CancellationToken cancellationToken = default)\n    {\n        var attempts = 0;\n        var exitCode = 0;\n        string? error = null;\n        string resolvedTunnelId = options.Region is not null ? $\"{tunnelId}.{options.RegionCode}\" : tunnelId;\n\n        while (attempts < _maxCliAttempts)\n        {\n            logger?.LogTrace(\"Creating dev tunnel '{TunnelId}' with options: {Options}\", tunnelId, options.ToLoggerString());\n            if (attempts++ > 1)\n            {\n                logger?.LogTrace(\"Attempt {Attempt} of {MaxAttempts} to create dev tunnel '{TunnelId}'\", attempts, _maxCliAttempts, tunnelId);\n            }\n            (var tunnel, exitCode, error) = await CallCliAsJsonAsync<DevTunnelStatus>((stdout, stderr, log, ct) => _cli.CreateTunnelAsync(tunnelId, options, stdout, stderr, log, ct),\n                \"tunnel\",","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.DevTunnels/DevTunnelCliClient.cs#L45-L81","documentation":"DevTunnelCliClient.GetVersionAsync parses the output of 'devtunnel --version'. If the parsed output does not yield a version and the CLI produced any output or error text, the client throws this DistributedApplicationException including the raw output and error so the underlying CLI failure is visible.","triggerScenarios":"Calling GetVersionAsync (directly or via DevTunnels resource startup) when the devtunnel CLI fails to produce a parseable version string — non-zero exit, empty output with error text, or unexpected output format from a changed CLI version.","commonSituations":"devtunnel CLI not logged in and prints an auth error; an old or preview devtunnel version whose --version output format differs; shell wrapper or PATH shim injecting extra output; CLI missing so errorWriter holds 'command not found'.","solutions":["Run 'devtunnel --version' manually and compare its output with what the client expects; upgrade or reinstall the CLI to a supported version","Run 'devtunnel user login' if the error text indicates authentication failure","Remove PATH shims/wrappers that add extra text to the CLI output","Check the message's Output/Error fields for the exact CLI failure before retrying"],"exampleFix":"// before\nvar version = await client.GetVersionAsync(); // throws when CLI output unparseable\n// after\nvar (stdout, stderr) = await CaptureAsync(() => new DevTunnelCli(path).GetVersionAsync());\nlogger.LogInformation(\"devtunnel version output: {Out} / {Err}\", stdout, stderr); // diagnose first\nvar version = await client.GetVersionAsync();","handlingStrategy":"try-catch","validationCode":"var probe = new StringBuilder();\nvar errs = new StringBuilder();\nawait cli.GetVersionAsync(probe, errs);\n// if probe output is empty or unparseable, fix the CLI before resource startup depends on it","typeGuard":null,"tryCatchPattern":"try\n{\n    var version = await client.GetVersionAsync();\n}\ncatch (DistributedApplicationException ex)\n{\n    logger.LogError(ex, \"devtunnel CLI version probe failed; check CLI install, login state, and version format.\");\n    throw; // fail fast: later tunnel operations will fail too\n}","preventionTips":["Keep the devtunnel CLI updated to a version the client supports","Run 'devtunnel user login' once per machine before starting the AppHost","Avoid PATH shims/wrappers that inject extra output into CLI stdout/stderr","Verify raw 'devtunnel --version' output after any CLI upgrade"],"tags":["devtunnels","cli","version-check","unexpected-output"],"backgroundTag":"unexpected-cli-output","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"}