dotnet/yarp · error · ArgumentException

Configuration Filter Error: Substitution for '{lookup}' in c

Error message

Configuration Filter Error: Substitution for '{lookup}' in cluster '{d.Key}' not found as an environment variable.

What it means

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.

Source

Thrown at samples/ReverseProxy.ConfigFilter.Sample/CustomConfigFilter.cs:40

        // as an environment variable. This is useful when hosted in Azure etc, as it enables a simple way to replace
        // destination addresses via the management console
        public ValueTask<ClusterConfig> ConfigureClusterAsync(ClusterConfig origCluster, CancellationToken cancel)
        {
            // Each cluster has a dictionary of destinations, which is read-only, so we'll create a new one with our updates 
            var newDests = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase);

            foreach (var d in origCluster.Destinations)
            {
                var origAddress = d.Value.Address;
                if (_exp.IsMatch(origAddress))
                {
                    // Get the name of the env variable from the destination and lookup value
                    var lookup = _exp.Matches(origAddress)[0].Groups[1].Value;
                    var newAddress = System.Environment.GetEnvironmentVariable(lookup);

                    if (string.IsNullOrWhiteSpace(newAddress))
                    {
                        throw new System.ArgumentException($"Configuration Filter Error: Substitution for '{lookup}' in cluster '{d.Key}' not found as an environment variable.");
                    }

                    // using c# 9 "with" to clone and initialize a new record
                    var modifiedDest = d.Value with { Address = newAddress };
                    newDests.Add(d.Key, modifiedDest);
                }
                else
                {
                    newDests.Add(d.Key, d.Value);
                }
            }
            return new ValueTask<ClusterConfig>(origCluster with { Destinations = newDests });
        }

        public ValueTask<RouteConfig> ConfigureRouteAsync(RouteConfig route, ClusterConfig cluster, CancellationToken cancel)
        {
            // Example: do not let config based routes take priority over code based routes.
            // Lower numbers are higher priority. Code routes default to 0.

View on GitHub (pinned to bd11867bee)

Solutions

  1. Set the referenced environment variable (e.g., export MyServiceHost=backend.internal) in the environment where YARP runs.
  2. Verify the placeholder name in the destination address exactly matches the environment variable name (case-sensitive on Linux).
  3. If the variable should be optional, wrap the lookup in a try/catch or provide a default instead of throwing.
  4. Use configuration-based substitution (e.g., appsettings.json with ${VAR} and a configuration provider) rather than the sample filter for production.

Example fix

// before — destination address in appsettings.json
"Address": "https://{{BackendHost}}/api"
// after — set the env var before launch
// bash: export BackendHost=10.0.0.5
// or hardcode: "Address": "https://10.0.0.5/api"
Defensive patterns

Strategy: validation

Validate before calling

string lookup = "MyServiceHost";
var resolved = Environment.GetEnvironmentVariable(lookup);
if (string.IsNullOrWhiteSpace(resolved))
{
    throw new InvalidOperationException($"Set the '{lookup}' environment variable before starting the proxy.");
}
// safe to use resolved in destination address

Type guard

// n/a — env var resolution is runtime string-based, not type-narrowing

Try / catch

try
{
    config = filter.ConfigureClusterAsync(cluster, ct).AsTask().Result;
}
catch (ArgumentException ex) when (ex.Message.Contains("not found as an environment variable"))
{
    logger.LogError(ex, "Environment variable substitution failed at startup; check env config.");
    throw;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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