microsoft/aspire · error · InvalidDataException

Container tunnel service

Error message

Container tunnel service {ts.Service?.Metadata.Name} should have valid address at this point

What it means

A container tunnel service reached endpoint-allocation without a complete address (AllocatedAddress/AllocatedPort), which should be guaranteed because the code waits for services to have complete addresses. This is an internal invariant check; hitting it means the tunnel's backing service never finished allocation.

Solutions

  1. Restart the AppHost so tunnel services re-allocate addresses.
  2. Verify the container runtime and networks are healthy (docker ps / kind cluster status).
  3. Update Aspire and file a bug if reproducible — the code marks this as an unreachable condition.
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    await appHost.StartAsync();
}
catch (InvalidDataException ex) when (ex.Message.Contains("tunnel service") && ex.Message.Contains("should have valid address"))
{
    // restart AppHost and container runtime; report upstream if persistent
}

Prevention

When it happens

Trigger: In AddContainerTunnelAllocatedEndpoints, ts.Service?.HasCompleteAddress is not true when processing tunnel services — the tunnel's DCP Service lacks a complete allocated address.

Common situations: Container/networking backends (docker, kind) failing to allocate ports; deleting or restarting the tunneled service mid-build; DCP races or bugs.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting/Dcp/DcpModelUtilities.cs:306

            ))
            .Where(ts =>
                ts.Service is not null &&
                string.Equals(ts.ResourceName, res.Name, StringComparisons.ResourceName) &&
                !string.IsNullOrEmpty(ts.EndpointName) &&
                !string.IsNullOrEmpty(ts.ContainerNetworkName)
            );

            foreach (var ts in tunnelServices)
            {
                if (!TryGetEndpoint(res, ts.EndpointName, out var endpoint))
                {
                    throw new InvalidDataException($"Service '{ts.Service!.Metadata.Name}' refers to endpoint '{ts.EndpointName}' that does not exist");
                }

                if (ts.Service?.HasCompleteAddress is not true)
                {
                    // This should never happen; if it does, we have a bug without a workaround for the user.
                    throw new InvalidDataException($"Container tunnel service {ts.Service?.Metadata.Name} should have valid address at this point");
                }

                var serverSvc = allAppResources.Get().OfType<ServiceWithModelResource>().FirstOrDefault(swr =>
                    string.Equals(swr.ModelResource.Name, ts.ResourceName, StringComparisons.ResourceName) &&
                    string.Equals(swr.EndpointAnnotation.Name, endpoint.Name, StringComparisons.EndpointAnnotationName)
                );
                if (serverSvc is null)
                {
                    // Should never happen -- we should have created a Service for every endpoint exposed from a resource.
                    throw new InvalidDataException($"The '{endpoint.Name}' on resource '{ts.ResourceName}' should have an associated DCP Service resource already set up");
                }

                var networkId = new NetworkIdentifier(ts.ContainerNetworkName!);
                var address = string.IsNullOrEmpty(ts.TunnelInstanceName) ? containerHostName : KnownHostNames.DefaultContainerTunnelHostName;
                var port = (int)ts.Service!.AllocatedPort!;

                var tunnelAllocatedEndpoint = new AllocatedEndpoint(
                    endpoint,

View on GitHub (pinned to 25830f84bd)