microsoft/aspire · critical · ArgumentException

must contain a local loopback address.

Error message

{KnownConfigNames.ResourceServiceEndpointUrl} must contain a local loopback address.

What it means

DashboardServiceHost resolves the resource service endpoint from KnownConfigNames.ResourceServiceEndpointUrl and requires it to be a local loopback address, since the dashboard connects to the AppHost's resource service locally. An ArgumentException is thrown when the configured URL host is not loopback (e.g. a public hostname or LAN IP).

Solutions

  1. Change ResourceServiceEndpointUrl to a loopback address (127.0.0.1, ::1, or localhost) with the correct port.
  2. If the AppHost truly runs remotely, tunnel the resource service to localhost (e.g. SSH/VS Code port forwarding) and use the local endpoint.
  3. Remove the ResourceServiceEndpointUrl override to let the host auto-discover the endpoint from the AppHost.
  4. Check for typos or stale hostnames in launchSettings/environment configuration.

Example fix

// before
// ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL=https://devbox.contoso.com:18975
// after
// ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL=http://127.0.0.1:18975  (or tunnel the remote port to localhost)
Defensive patterns

Strategy: validation

Validate before calling

var url = new Uri(Environment.GetEnvironmentVariable("ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL")!);
var loopback = new[] { IPAddress.Loopback, IPAddress.IPv6Loopback };
var isLoopback = url.Host is "localhost" || (IPAddress.TryParse(url.Host, out var ip) && loopback.Contains(ip));
if (!isLoopback) throw new ArgumentException($"{url} must be a loopback address.");

Type guard

bool IsLoopback(Uri u) => u.Host == "localhost" || (IPAddress.TryParse(u.Host, out var ip) && (IPAddress.Loopback.Equals(ip) || IPAddress.IPv6Loopback.Equals(ip)));

Try / catch

try { startDashboardHost(); } catch (ArgumentException ex) when (ex.Message.Contains("loopback")) { logger.LogError(ex, "Fix ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL to point at 127.0.0.1/localhost."); }

Prevention

When it happens

Trigger: Setting ResourceServiceEndpointUrl (environment/config) to a non-loopback host such as https://myhost.example.com or a LAN IP, then starting the dashboard service host.

Common situations: Container/remote-dev setups where developers point the dashboard at a remote AppHost; misconfigured port-forward URLs; copying config from a machine with a different hostname.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/8e97085bc024e219. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting/Dashboard/DashboardServiceHost.cs:208

            return new ResourceServiceEndpointInfo(ip, effectivePort, UseListenLocalhost: false, scheme);
        }
        else if (configuredUri.IsLoopback || IsLocalhostOrLocalhostTld(configuredUri))
        {
            // For "localhost" or *.localhost hosts, bind to both IPv4 and IPv6 loopback.
            // Kestrel does not support ListenLocalhost with port 0, so fall back to
            // binding on IPv4 loopback when a dynamic port is needed.
            if (effectivePort == 0)
            {
                return new ResourceServiceEndpointInfo(IPAddress.Loopback, Port: 0, UseListenLocalhost: false, scheme);
            }
            else
            {
                return new ResourceServiceEndpointInfo(IPAddress.Loopback, effectivePort, UseListenLocalhost: true, scheme);
            }
        }
        else
        {
            throw new ArgumentException($"{KnownConfigNames.ResourceServiceEndpointUrl} must contain a local loopback address.");
        }
    }

    /// <summary>
    /// Determines the scheme for the resource service endpoint. When a URI is explicitly
    /// configured, its scheme is used. When no URI is provided, defaults to HTTPS unless
    /// unsecured transport is explicitly allowed.
    /// </summary>
    internal static string ResolveScheme(Uri? configuredUri, bool allowUnsecuredTransport)
    {
        if (configuredUri is not null)
        {
            return configuredUri.Scheme;
        }

        return allowUnsecuredTransport ? "http" : "https";
    }

View on GitHub (pinned to 25830f84bd)