{"record":{"id":"c3486ba8fc4a3054","repo":"dotnet/yarp","slug":"error-resolving-destinations-for-cluster-cluster","errorCode":null,"errorMessage":"Error resolving destinations for cluster {cluster.ClusterId}","messagePattern":"Error resolving destinations for cluster (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Management/ProxyConfigManager.cs","lineNumber":382,"sourceCode":"                // Resolve destinations if there are any.\n                var task = _destinationResolver.ResolveDestinationsAsync(destinations, cancellationToken);\n                resolverTasks.Add((i, task));\n            }\n        }\n\n        if (resolverTasks.Count > 0)\n        {\n            foreach (var (i, task) in resolverTasks)\n            {\n                ResolvedDestinationCollection resolvedDestinations;\n                try\n                {\n                    resolvedDestinations = await task;\n                }\n                catch (Exception exception)\n                {\n                    var cluster = clusters[i];\n                    throw new InvalidOperationException($\"Error resolving destinations for cluster {cluster.ClusterId}\", exception);\n                }\n\n                clusters[i] = clusters[i] with { Destinations = resolvedDestinations.Destinations };\n                if (resolvedDestinations.ChangeToken is { } token)\n                {\n                    changeTokens ??= new();\n                    changeTokens.Add(token);\n                }\n            }\n\n            IChangeToken changeToken;\n            if (changeTokens is not null)\n            {\n                // Combine change tokens from the resolver with the configuration's existing change token.\n                changeTokens.Add(config.ChangeToken);\n                changeToken = new CompositeChangeToken(changeTokens);\n            }\n            else","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Management/ProxyConfigManager.cs#L364-L400","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Check the `InnerException` of this `InvalidOperationException` for the resolver-specific error (e.g., `SocketException` for DNS failures).","Verify all destination hostnames in the cluster config are resolvable from the YARP host — run `nslookup` or `dig` to confirm.","If using `DnsDestinationResolver`, ensure DNS servers are reachable and the hostnames are registered.","If using a custom `IDestinationResolver`, add logging and error handling inside it to surface the root cause.","If a destination is temporarily unresolvable, consider removing it from config until it's available, or add retry logic to the resolver.","Ensure service discovery infrastructure (Consul, Kubernetes services, etc.) is healthy before starting YARP."],"exampleFix":"// before — cluster references an unresolvable hostname\nvar clusters = new[]\n{\n    new ClusterConfig\n    {\n        ClusterId = \"my-cluster\",\n        Destinations = new Dictionary<string, DestinationConfig>\n        {\n            [\"d1\"] = new() { Address = \"http://nonexistent-host.local:8080\" }\n        }\n    }\n};\n// after — use a resolvable hostname or IP\nvar clusters = new[]\n{\n    new ClusterConfig\n    {\n        ClusterId = \"my-cluster\",\n        Destinations = new Dictionary<string, DestinationConfig>\n        {\n            [\"d1\"] = new() { Address = \"http://my-service.default.svc.cluster.local:8080\" }\n        }\n    }\n};","handlingStrategy":"try-catch","validationCode":"// Pre-resolve destination hostnames before config load\nforeach (var dest in cluster.Destinations?.Values ?? Array.Empty<DestinationConfig>())\n{\n    var host = new Uri(dest.Address).Host;\n    try { await Dns.GetHostAddressesAsync(host); }\n    catch { logger.LogWarning(\"Cannot resolve destination host: {Host}\", host); }\n}","typeGuard":"// No type guard — destination resolution failures are runtime/DNS conditions.","tryCatchPattern":"// This propagates through the InitialLoadAsync wrapper (error 27).\n// Catch and inspect at the startup level:\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Error resolving destinations\"))\n{\n    var clusterId = ex.Message; // contains the cluster ID\n    var rootCause = ex.InnerException; // DNS SocketException, etc.\n    logger.LogCritical(\"Destination resolution failed: {Cluster}. Cause: {Cause}\", clusterId, rootCause?.Message);\n}","preventionTips":["Verify all destination hostnames are resolvable from the YARP host before deploying.","If using DnsDestinationResolver, ensure DNS infrastructure is healthy.","Log the cluster ID and inner exception to quickly identify which destination failed."],"tags":["configuration","destination-resolution","dns","service-discovery","startup"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}