{"record":{"id":"ad75989d2ca2abff","repo":"dotnet/yarp","slug":"a-header-name-is-required","errorCode":null,"errorMessage":"A header name is required.","messagePattern":"A header name is required\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Routing/HeaderMatcher.cs","lineNumber":24,"sourceCode":"using System.Linq;\nusing Microsoft.Net.Http.Headers;\nusing Yarp.ReverseProxy.Configuration;\n\nnamespace Yarp.ReverseProxy.Routing;\n\n/// <summary>\n/// A request header matcher used during routing.\n/// </summary>\ninternal sealed class HeaderMatcher\n{\n    /// <summary>\n    /// Creates a new instance.\n    /// </summary>\n    public HeaderMatcher(string name, IReadOnlyList<string>? values, HeaderMatchMode mode, bool isCaseSensitive)\n    {\n        if (string.IsNullOrEmpty(name))\n        {\n            throw new ArgumentException(\"A header name is required.\", nameof(name));\n        }\n        if ((mode != HeaderMatchMode.Exists && mode != HeaderMatchMode.NotExists)\n            && (values is null || values.Count == 0))\n        {\n            throw new ArgumentException(\"Header values must have at least one value.\", nameof(values));\n        }\n        if ((mode == HeaderMatchMode.Exists || mode == HeaderMatchMode.NotExists) && values?.Count > 0)\n        {\n            throw new ArgumentException($\"Header values must not be specified when using '{mode}'.\", nameof(values));\n        }\n        if (values is not null && values.Any(string.IsNullOrEmpty))\n        {\n            throw new ArgumentNullException(nameof(values), \"Header values must be not be empty.\");\n        }\n\n        Name = name;\n        Values = values?.ToArray() ?? Array.Empty<string>();\n        Mode = mode;","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Routing/HeaderMatcher.cs#L6-L42","documentation":"The `HeaderMatcher` constructor validates that a non-empty header name is provided, since a header matcher with no name cannot match anything. This validation runs during config verification when route header match rules are converted from `HeaderMatchConfig` to `HeaderMatcher` instances. The `ArgumentException` identifies the null/empty name as the problem.","triggerScenarios":"A route in the config defines a header match with an empty or null `Header` field (e.g., `{ \"Match\": { \"Headers\": [{ \"Header\": \"\", \"Values\": [\"x\"] }] } }`). During `VerifyRoutesAsync`, the config validator constructs a `HeaderMatcher` for each header rule, and the constructor throws because `name` is empty.","commonSituations":"A typo or placeholder in the route configuration leaves the header name empty. A dynamic config generator (e.g., a Kubernetes ingress controller or custom config provider) produces a header match with a null header name due to a missing field in the source data. Configuration was copy-pasted and the header name wasn't updated.","solutions":["Inspect the route configuration (appsettings.json, in-memory config, or custom provider output) for header match rules with empty or missing `Header` fields and provide a valid header name.","If config is generated dynamically, add validation at the generation layer to reject or skip header matches with empty names before they reach YARP.","Search for `\"Header\": \"\"` or `\"Header\": null` in the configuration source.","Ensure the header name is a valid HTTP header name (e.g., `X-Custom-Header`, `Authorization`, `Accept`)."],"exampleFix":"// before — appsettings.json with empty header name\n\"Routes\": {\n  \"my-route\": {\n    \"Match\": {\n      \"Path\": \"/api\",\n      \"Headers\": [\n        { \"Header\": \"\", \"Values\": [\"value1\"] } // bug!\n      ]\n    }\n  }\n}\n// after — provide a valid header name\n\"Routes\": {\n  \"my-route\": {\n    \"Match\": {\n      \"Path\": \"/api\",\n      \"Headers\": [\n        { \"Header\": \"X-Api-Key\", \"Values\": [\"secret123\"] }\n      ]\n    }\n  }\n}","handlingStrategy":"validation","validationCode":"// Validate header match config before adding to route\nstatic bool IsValidHeaderMatch(HeaderMatchConfig match)\n{\n    return !string.IsNullOrEmpty(match.Header);\n}","typeGuard":"static bool IsValidHeaderMatcherConfig(string? name, IReadOnlyList<string>? values, string mode)\n    => !string.IsNullOrEmpty(name)\n    && ((mode is \"Exists\" or \"NotExists\") || (values is { Count: > 0 }));","tryCatchPattern":"// Not applicable — fix the configuration to provide a valid header name.\n// The error surfaces during config validation at startup.","preventionTips":["Validate header match config before deploying — check for empty Header fields.","If generating config programmatically, skip or reject entries with empty header names.","Search appsettings.json for `\"Header\": \"\"` or `\"Header\": null`."],"tags":["configuration","routing","header-matcher","validation"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}