{"record":{"id":"5526bbc83984201e","repo":"microsoft/aspire","slug":"failed-to-get-user-login-status-exit-code-exitcode-error","errorCode":null,"errorMessage":"Failed to get user login status. Exit code {exitCode}: {error}","messagePattern":"Failed to get user login status\\. Exit code (.+?): (.+?)","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.DevTunnels/DevTunnelCliClient.cs","lineNumber":268,"sourceCode":"        return result ?? throw new DistributedApplicationException($\"Failed to delete port '{portNumber}' on dev tunnel '{tunnelId}'. Exit code {exitCode}: {error}\");\n    }\n\n    public async Task<DevTunnelAccessStatus> GetAccessAsync(string tunnelId, int? portNumber = null, ILogger? logger = default, CancellationToken cancellationToken = default)\n    {\n        logger?.LogTrace(\"Getting access details for {PortInfo}dev tunnel '{TunnelId}'.\", portNumber.HasValue ? $\"port '{portNumber}' on \" : string.Empty, tunnelId);\n        var (access, exitCode, error) = await CallCliAsJsonAsync<DevTunnelAccessStatus>(\n            (stdout, stderr, log, ct) => _cli.ListAccessAsync(tunnelId, portNumber, stdout, stderr, log, ct),\n            logger, cancellationToken).ConfigureAwait(false);\n        return access ?? throw new DistributedApplicationException($\"Failed to get access details for '{tunnelId}'{(portNumber.HasValue ? $\" port {portNumber}\" : \"\")}. Exit code {exitCode}: {error}\");\n    }\n\n    public async Task<UserLoginStatus> GetUserLoginStatusAsync(ILogger? logger = default, CancellationToken cancellationToken = default)\n    {\n        logger?.LogTrace(\"Getting dev tunnel user login status.\");\n        var (login, exitCode, error) = await CallCliAsJsonAsync<UserLoginStatus>(\n            _cli.UserStatusAsync,\n            logger, cancellationToken).ConfigureAwait(false);\n        return login ?? throw new DistributedApplicationException($\"Failed to get user login status. Exit code {exitCode}: {error}\");\n    }\n\n    public async Task<UserLoginStatus> UserLoginAsync(LoginProvider provider, ILogger? logger = default, CancellationToken cancellationToken = default)\n    {\n        logger?.LogTrace(\"Logging in to dev tunnel service using {LoginProvider}.\", provider);\n        var exitCode = provider switch\n        {\n            LoginProvider.Microsoft => await _cli.UserLoginMicrosoftAsync(logger, cancellationToken).ConfigureAwait(false),\n            LoginProvider.GitHub => await _cli.UserLoginGitHubAsync(logger, cancellationToken).ConfigureAwait(false),\n            _ => throw new ArgumentException(\"Unsupported provider. Supported providers are 'microsoft' and 'github'.\", nameof(provider)),\n        };\n\n        if (exitCode == 0)\n        {\n            // Login succeeded, get the login status\n            return await GetUserLoginStatusAsync(logger, cancellationToken).ConfigureAwait(false);\n        }\n","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.DevTunnels/DevTunnelCliClient.cs#L250-L286","documentation":"GetUserLoginStatusAsync invokes `devtunnel user status` and deserializes the login state. A non-zero CLI exit means no status object was returned, so this DistributedApplicationException is thrown including the exit code and CLI error text.","triggerScenarios":"Calling GetUserLoginStatusAsync (directly or via UserLoginAsync) when the devtunnel CLI is missing/broken, the user is not authenticated, or the CLI fails with an error instead of emitting status JSON.","commonSituations":"Fresh machines where `devtunnel user login` was never run; expired tokens; CI containers without the devtunnel CLI on PATH; proxy/network failures reaching the tunnel service.","solutions":["Run `devtunnel user login` interactively to establish credentials, then retry","Verify the devtunnel CLI is installed and on PATH (`devtunnel --version`)","Inspect the exit code and error text appended to the message for the root cause","In CI, provision devtunnel credentials (e.g. via `devtunnel user login -g` with a token) before the app host starts"],"exampleFix":"// before\nvar status = await client.GetUserLoginStatusAsync(); // throws when logged out\n// after\ntry\n{\n    var status = await client.GetUserLoginStatusAsync();\n}\ncatch (DistributedApplicationException ex)\n{\n    logger.LogWarning(ex, \"devtunnel CLI could not report login status; prompting login\");\n}","handlingStrategy":"try-catch","validationCode":"var which = Environment.GetEnvironmentVariable(\"PATH\");\n// ensure devtunnel CLI present:\nvar cliPath = Environment.GetEnvironmentVariable(\"PATH\")!.Split(':').Select(d => Path.Combine(d, \"devtunnel\")).FirstOrDefault(File.Exists);\nif (cliPath is null) throw new InvalidOperationException(\"devtunnel CLI not installed\");","typeGuard":"static bool IsKnownLoginStatus(UserLoginStatus? s) => s is not null;","tryCatchPattern":"try { return await client.GetUserLoginStatusAsync(logger, ct); }\ncatch (DistributedApplicationException ex) { logger.LogWarning(ex, \"Not logged in to dev tunnels\"); return null; }","preventionTips":["Install the devtunnel CLI and run `devtunnel user login` before starting the app host","In CI, provision non-interactive credentials","Check `devtunnel user status` manually when diagnosing"],"tags":["devtunnels","cli","authentication"],"backgroundTag":"authentication-required","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"}