{"record":{"id":"7a2ba83a98ddea34","repo":"dotnet/yarp","slug":"configuration-filter-error-substitution-for-loo","errorCode":null,"errorMessage":"Configuration Filter Error: Substitution for '{lookup}' in cluster '{d.Key}' not found as an environment variable.","messagePattern":"Configuration Filter Error: Substitution for '(.+?)' in cluster '(.+?)' not found as an environment variable\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"samples/ReverseProxy.ConfigFilter.Sample/CustomConfigFilter.cs","lineNumber":40,"sourceCode":"        // as an environment variable. This is useful when hosted in Azure etc, as it enables a simple way to replace\n        // destination addresses via the management console\n        public ValueTask<ClusterConfig> ConfigureClusterAsync(ClusterConfig origCluster, CancellationToken cancel)\n        {\n            // Each cluster has a dictionary of destinations, which is read-only, so we'll create a new one with our updates \n            var newDests = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase);\n\n            foreach (var d in origCluster.Destinations)\n            {\n                var origAddress = d.Value.Address;\n                if (_exp.IsMatch(origAddress))\n                {\n                    // Get the name of the env variable from the destination and lookup value\n                    var lookup = _exp.Matches(origAddress)[0].Groups[1].Value;\n                    var newAddress = System.Environment.GetEnvironmentVariable(lookup);\n\n                    if (string.IsNullOrWhiteSpace(newAddress))\n                    {\n                        throw new System.ArgumentException($\"Configuration Filter Error: Substitution for '{lookup}' in cluster '{d.Key}' not found as an environment variable.\");\n                    }\n\n                    // using c# 9 \"with\" to clone and initialize a new record\n                    var modifiedDest = d.Value with { Address = newAddress };\n                    newDests.Add(d.Key, modifiedDest);\n                }\n                else\n                {\n                    newDests.Add(d.Key, d.Value);\n                }\n            }\n            return new ValueTask<ClusterConfig>(origCluster with { Destinations = newDests });\n        }\n\n        public ValueTask<RouteConfig> ConfigureRouteAsync(RouteConfig route, ClusterConfig cluster, CancellationToken cancel)\n        {\n            // Example: do not let config based routes take priority over code based routes.\n            // Lower numbers are higher priority. Code routes default to 0.","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/samples/ReverseProxy.ConfigFilter.Sample/CustomConfigFilter.cs#L22-L58","documentation":"Thrown by the CustomConfigFilter sample when a destination address contains a {{EnvVarName}} placeholder but the named environment variable is unset or whitespace. The filter iterates cluster destinations, regex-matches {{key}} tokens, and resolves them via Environment.GetEnvironmentVariable, failing if the lookup yields nothing. This is sample-only behavior demonstrating IProxyConfigFilter, not built into the runtime.","triggerScenarios":"A cluster destination Address is set to a value like \"https://{{MyServiceHost}}/path\" and the environment has no MyServiceHost variable (or it is empty/whitespace) when the proxy configuration is loaded. The exception surfaces during ConfigureClusterAsync at startup or on config reload.","commonSituations":"Forgetting to set the environment variable in the deployment environment (Azure App Service, containers, local dev). Typo between the placeholder name and the actual env var name. Variable set in one environment (dev) but missing in another (staging/prod). Using a placeholder syntax that doesn't match the {{\\w+}} regex.","solutions":["Set the referenced environment variable (e.g., export MyServiceHost=backend.internal) in the environment where YARP runs.","Verify the placeholder name in the destination address exactly matches the environment variable name (case-sensitive on Linux).","If the variable should be optional, wrap the lookup in a try/catch or provide a default instead of throwing.","Use configuration-based substitution (e.g., appsettings.json with ${VAR} and a configuration provider) rather than the sample filter for production."],"exampleFix":"// before — destination address in appsettings.json\n\"Address\": \"https://{{BackendHost}}/api\"\n// after — set the env var before launch\n// bash: export BackendHost=10.0.0.5\n// or hardcode: \"Address\": \"https://10.0.0.5/api\"","handlingStrategy":"validation","validationCode":"string lookup = \"MyServiceHost\";\nvar resolved = Environment.GetEnvironmentVariable(lookup);\nif (string.IsNullOrWhiteSpace(resolved))\n{\n    throw new InvalidOperationException($\"Set the '{lookup}' environment variable before starting the proxy.\");\n}\n// safe to use resolved in destination address","typeGuard":"// n/a — env var resolution is runtime string-based, not type-narrowing","tryCatchPattern":"try\n{\n    config = filter.ConfigureClusterAsync(cluster, ct).AsTask().Result;\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"not found as an environment variable\"))\n{\n    logger.LogError(ex, \"Environment variable substitution failed at startup; check env config.\");\n    throw;\n}","preventionTips":["Document every {{Placeholder}} name and require it in deployment runbooks.","Add a startup health check that asserts all expected env vars are set before serving traffic.","Use machine/environment-agnostic config and inject secrets via a secrets manager."],"tags":["configuration","environment-variables","config-filter","sample","startup"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}