dotnet/yarp · error · InvalidOperationException

Error resolving destinations for cluster {cluster.ClusterId}

Error message

Error resolving destinations for cluster {cluster.ClusterId}

What it means

When a non-default `IDestinationResolver` is registered (e.g., `DnsDestinationResolver`), YARP resolves destination addresses for each cluster with destinations during config load. If `ResolveDestinationsAsync` throws for a specific cluster, YARP wraps the exception with the cluster ID for identification and rethrows as `InvalidOperationException`. This prevents silently proxying to unresolved destinations.

Source

Thrown at src/ReverseProxy/Management/ProxyConfigManager.cs:382

                // Resolve destinations if there are any.
                var task = _destinationResolver.ResolveDestinationsAsync(destinations, cancellationToken);
                resolverTasks.Add((i, task));
            }
        }

        if (resolverTasks.Count > 0)
        {
            foreach (var (i, task) in resolverTasks)
            {
                ResolvedDestinationCollection resolvedDestinations;
                try
                {
                    resolvedDestinations = await task;
                }
                catch (Exception exception)
                {
                    var cluster = clusters[i];
                    throw new InvalidOperationException($"Error resolving destinations for cluster {cluster.ClusterId}", exception);
                }

                clusters[i] = clusters[i] with { Destinations = resolvedDestinations.Destinations };
                if (resolvedDestinations.ChangeToken is { } token)
                {
                    changeTokens ??= new();
                    changeTokens.Add(token);
                }
            }

            IChangeToken changeToken;
            if (changeTokens is not null)
            {
                // Combine change tokens from the resolver with the configuration's existing change token.
                changeTokens.Add(config.ChangeToken);
                changeToken = new CompositeChangeToken(changeTokens);
            }
            else

View on GitHub (pinned to bd11867bee)

Solutions

  1. Check the `InnerException` of this `InvalidOperationException` for the resolver-specific error (e.g., `SocketException` for DNS failures).
  2. Verify all destination hostnames in the cluster config are resolvable from the YARP host — run `nslookup` or `dig` to confirm.
  3. If using `DnsDestinationResolver`, ensure DNS servers are reachable and the hostnames are registered.
  4. If using a custom `IDestinationResolver`, add logging and error handling inside it to surface the root cause.
  5. If a destination is temporarily unresolvable, consider removing it from config until it's available, or add retry logic to the resolver.
  6. Ensure service discovery infrastructure (Consul, Kubernetes services, etc.) is healthy before starting YARP.

Example fix

// before — cluster references an unresolvable hostname
var clusters = new[]
{
    new ClusterConfig
    {
        ClusterId = "my-cluster",
        Destinations = new Dictionary<string, DestinationConfig>
        {
            ["d1"] = new() { Address = "http://nonexistent-host.local:8080" }
        }
    }
};
// after — use a resolvable hostname or IP
var clusters = new[]
{
    new ClusterConfig
    {
        ClusterId = "my-cluster",
        Destinations = new Dictionary<string, DestinationConfig>
        {
            ["d1"] = new() { Address = "http://my-service.default.svc.cluster.local:8080" }
        }
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-resolve destination hostnames before config load
foreach (var dest in cluster.Destinations?.Values ?? Array.Empty<DestinationConfig>())
{
    var host = new Uri(dest.Address).Host;
    try { await Dns.GetHostAddressesAsync(host); }
    catch { logger.LogWarning("Cannot resolve destination host: {Host}", host); }
}

Type guard

// No type guard — destination resolution failures are runtime/DNS conditions.

Try / catch

// This propagates through the InitialLoadAsync wrapper (error 27).
// Catch and inspect at the startup level:
catch (InvalidOperationException ex) when (ex.Message.Contains("Error resolving destinations"))
{
    var clusterId = ex.Message; // contains the cluster ID
    var rootCause = ex.InnerException; // DNS SocketException, etc.
    logger.LogCritical("Destination resolution failed: {Cluster}. Cause: {Cause}", clusterId, rootCause?.Message);
}

Prevention

When it happens

Trigger: `AddDnsDestinationResolver()` is registered and a cluster has destinations with hostnames that need DNS resolution. `ResolveDestinationsAsync` throws — e.g., DNS lookup fails, a hostname is unresolvable, or a custom resolver implementation encounters an error. The catch at line 379 wraps it with the cluster's ID.

Common situations: A cluster destination is configured with a hostname that doesn't exist in DNS. The DNS server is temporarily unavailable during YARP startup. A custom `IDestinationResolver` implementation throws due to a bug or connectivity issue to its backing store (e.g., a service discovery API is down). A Kubernetes-based deployment references a service that hasn't been created yet.

Related errors


AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13). Data as JSON: /api/errors/c3486ba8fc4a3054. Report an issue: GitHub.