dotnet/yarp · error · ArgumentException

Header values must not be specified when using '{mode}'.

Error message

Header values must not be specified when using '{mode}'.

What it means

Thrown by the HeaderMatcher constructor when a header match Mode of Exists or NotExists is selected but one or more match Values are also supplied. Exists/NotExists only test header presence, so supplying values is contradictory. The argument exception targets the `values` parameter so the caller knows which input is at fault.

Source

Thrown at src/ReverseProxy/Routing/HeaderMatcher.cs:33

internal sealed class HeaderMatcher
{
    /// <summary>
    /// Creates a new instance.
    /// </summary>
    public HeaderMatcher(string name, IReadOnlyList<string>? values, HeaderMatchMode mode, bool isCaseSensitive)
    {
        if (string.IsNullOrEmpty(name))
        {
            throw new ArgumentException("A header name is required.", nameof(name));
        }
        if ((mode != HeaderMatchMode.Exists && mode != HeaderMatchMode.NotExists)
            && (values is null || values.Count == 0))
        {
            throw new ArgumentException("Header values must have at least one value.", nameof(values));
        }
        if ((mode == HeaderMatchMode.Exists || mode == HeaderMatchMode.NotExists) && values?.Count > 0)
        {
            throw new ArgumentException($"Header values must not be specified when using '{mode}'.", nameof(values));
        }
        if (values is not null && values.Any(string.IsNullOrEmpty))
        {
            throw new ArgumentNullException(nameof(values), "Header values must be not be empty.");
        }

        Name = name;
        Values = values?.ToArray() ?? Array.Empty<string>();
        Mode = mode;
        Comparison = isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
        Separator = name.Equals(HeaderNames.Cookie, StringComparison.OrdinalIgnoreCase) ? ';' : ',';
    }

    /// <summary>
    /// Name of the header to look for.
    /// </summary>
    public string Name { get; }

View on GitHub (pinned to bd11867bee)

Solutions

  1. If you only need presence checks, remove all `values` entries for that header matcher (set Mode to Exists/NotExists and omit Values).
  2. If you actually want to match a header value, change Mode to ExactHeader, HeaderPrefix, ExactHeaderPrefix, or Contains and keep the values.
  3. Validate the HeaderMatcher config object before construction: for Exists/NotExists modes assert values is null or empty.

Example fix

// before
new HeaderMatcher("X-Flag", new[] { "1" }, HeaderMatchMode.Exists, isCaseSensitive: true);
// after
new HeaderMatcher("X-Flag", values: null, HeaderMatchMode.Exists, isCaseSensitive: true);
Defensive patterns

Strategy: validation

Validate before calling

if ((mode == HeaderMatchMode.Exists || mode == HeaderMatchMode.NotExists) && values?.Count > 0)
    throw new InvalidOperationException("Exists/NotExists modes cannot take values.");

Type guard

static bool IsValidHeaderMatcherConfig(HeaderMatchMode mode, IReadOnlyList<string>? values) =>
    (mode == HeaderMatchMode.Exists || mode == HeaderMatchMode.NotExists)
        ? values is null || values.Count == 0
        : values is not null && values.Count > 0;

Prevention

When it happens

Trigger: Constructing `new HeaderMatcher(name, values, HeaderMatchMode.Exists, ...)` or `HeaderMatchMode.NotExists` with a non-empty `values` list. Also reached indirectly when YARP config binds a route's Header values while Mode is set to Exists/NotExists.

Common situations: Copied config from an ExactHeader/PrefixHeader rule and left the `values` array populated after switching Mode to `Exists`. YAML/JSON config that sets both `values` and `mode: HeaderPrefix`->`Exists`. Migration from an older config schema that inferred mode.

Related errors


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