microsoft/aspire · error · DistributedApplicationException
Failed to get access details for
Error message
Failed to get access details for '{tunnelId}'{portNumber}. Exit code {exitCode}: {error} What it means
GetAccessAsync runs `devtunnel access list` for a tunnel (optionally a specific port) and deserializes the JSON. When the CLI exits non-zero and no access status can be produced, this DistributedApplicationException is thrown with the exit code and CLI error output.
Solutions
- Confirm the tunnelId exists (`devtunnel list`) and has not expired (expiration is 1 hour to 30 days)
- Re-authenticate with `devtunnel user login` if the CLI error indicates not logged in
- Check the error text in the message for the underlying CLI reason
- Only query access for ports you previously created/configured
Example fix
// before
var status = await client.GetAccessAsync("staging-tunnel", 443); // throws if tunnel missing
// after
var tunnels = await client.ListTunnelsAsync();
if (tunnels.Any(t => t.TunnelId == "staging-tunnel"))
{
var status = await client.GetAccessAsync("staging-tunnel", 443);
} Defensive patterns
Strategy: try-catch
Validate before calling
var tunnels = await client.ListTunnelsAsync(logger, ct);
if (!tunnels.Any(t => t.TunnelId == tunnelId)) throw new InvalidOperationException($"Tunnel '{tunnelId}' not found"); Type guard
static bool IsValidTunnelId(string? id) => !string.IsNullOrEmpty(id) && id.All(c => char.IsAsciiLetterOrDigit(c) || c == '-');
Try / catch
try { var access = await client.GetAccessAsync(tunnelId, port, logger, ct); }
catch (DistributedApplicationException ex) { logger.LogError(ex, "Access lookup failed for {Tunnel}", tunnelId); } Prevention
- Confirm tunnel existence and non-expiration before querying access
- Re-login with devtunnel when auth-related exit codes appear
- Only query ports you configured
When it happens
Trigger: Calling GetAccessAsync for a tunnelId that does not exist or expired, an unauthenticated/expired devtunnel login, a port that has no access configuration, or any CLI invocation failing to produce JSON.
Common situations: Tunnel was auto-deleted after expiration; tunnelId derived from a different AppHost name/hash; anonymous access probing before login; querying a port before access was set.
Related errors
- CLI path must be provided
- Failed to delete port
- Failed to get devtunnel CLI version. Output
- Failed to get user login status. Exit code
- Failed to parse JSON output into type
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/3c75a75e30c862e2.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.DevTunnels/DevTunnelCliClient.cs:259
throw new DistributedApplicationException($"Failed to create port '{portNumber}' for tunnel '{tunnelId}' after {attempts} attempts. Exit code {exitCode}: {error}");
}
public async Task<DevTunnelPortDeleteResult> DeletePortAsync(string tunnelId, int portNumber, ILogger? logger = default, CancellationToken cancellationToken = default)
{
logger?.LogTrace("Deleting port '{PortNumber}' on dev tunnel '{TunnelId}'.", portNumber, tunnelId);
var (result, exitCode, error) = await CallCliAsJsonAsync<DevTunnelPortDeleteResult>(
(stdout, stderr, log, ct) => _cli.DeletePortAsync(tunnelId, portNumber, stdout, stderr, log, ct),
logger, cancellationToken).ConfigureAwait(false);
return result ?? throw new DistributedApplicationException($"Failed to delete port '{portNumber}' on dev tunnel '{tunnelId}'. Exit code {exitCode}: {error}");
}
public async Task<DevTunnelAccessStatus> GetAccessAsync(string tunnelId, int? portNumber = null, ILogger? logger = default, CancellationToken cancellationToken = default)
{
logger?.LogTrace("Getting access details for {PortInfo}dev tunnel '{TunnelId}'.", portNumber.HasValue ? $"port '{portNumber}' on " : string.Empty, tunnelId);
var (access, exitCode, error) = await CallCliAsJsonAsync<DevTunnelAccessStatus>(
(stdout, stderr, log, ct) => _cli.ListAccessAsync(tunnelId, portNumber, stdout, stderr, log, ct),
logger, cancellationToken).ConfigureAwait(false);
return access ?? throw new DistributedApplicationException($"Failed to get access details for '{tunnelId}'{(portNumber.HasValue ? $" port {portNumber}" : "")}. Exit code {exitCode}: {error}");
}
public async Task<UserLoginStatus> GetUserLoginStatusAsync(ILogger? logger = default, CancellationToken cancellationToken = default)
{
logger?.LogTrace("Getting dev tunnel user login status.");
var (login, exitCode, error) = await CallCliAsJsonAsync<UserLoginStatus>(
_cli.UserStatusAsync,
logger, cancellationToken).ConfigureAwait(false);
return login ?? throw new DistributedApplicationException($"Failed to get user login status. Exit code {exitCode}: {error}");
}
public async Task<UserLoginStatus> UserLoginAsync(LoginProvider provider, ILogger? logger = default, CancellationToken cancellationToken = default)
{
logger?.LogTrace("Logging in to dev tunnel service using {LoginProvider}.", provider);
var exitCode = provider switch
{
LoginProvider.Microsoft => await _cli.UserLoginMicrosoftAsync(logger, cancellationToken).ConfigureAwait(false),
LoginProvider.GitHub => await _cli.UserLoginGitHubAsync(logger, cancellationToken).ConfigureAwait(false),View on GitHub (pinned to 25830f84bd)