{"record":{"id":"df03d74296cb5a92","repo":"dotnet/yarp","slug":"headername-cannot-be-null-or-empty","errorCode":null,"errorMessage":"'headerName' cannot be null or empty.","messagePattern":"'headerName' cannot be null or empty\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Transforms/RequestHeaderClientCertTransform.cs","lineNumber":18,"sourceCode":"// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Yarp.ReverseProxy.Transforms;\n\n/// <summary>\n/// Base64 encodes the client certificate (if any) and sets it as the header value.\n/// </summary>\npublic class RequestHeaderClientCertTransform : RequestTransform\n{\n    public RequestHeaderClientCertTransform(string headerName)\n    {\n        if (string.IsNullOrEmpty(headerName))\n        {\n            throw new ArgumentException($\"'{nameof(headerName)}' cannot be null or empty.\", nameof(headerName));\n        }\n\n        HeaderName = headerName;\n    }\n\n    internal string HeaderName { get; }\n\n    /// <inheritdoc/>\n    public override ValueTask ApplyAsync(RequestTransformContext context)\n    {\n        ArgumentNullException.ThrowIfNull(context);\n\n        RemoveHeader(context, HeaderName);\n\n        var clientCert = context.HttpContext.Connection.ClientCertificate;\n        if (clientCert is not null)\n        {\n            var encoded = Convert.ToBase64String(clientCert.RawData);","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Transforms/RequestHeaderClientCertTransform.cs#L1-L36","documentation":"RequestHeaderClientCertTransform's constructor rejects a null or empty headerName with ArgumentException. The transform needs a concrete header name to write the base64-encoded client certificate into, so an empty name is a programming error, not a recoverable runtime condition.","triggerScenarios":"Calling `new RequestHeaderClientCertTransform(headerName)` where headerName is null, string.Empty, or whitespace-only. In config-driven flow, this fires if a custom factory or AddTransform callback passes an empty value; the built-in factories always supply the header name from config keys.","commonSituations":"Programmatically adding transforms via AddTransform with a variable that resolved to empty; a config value that is an empty string reaching a custom factory; refactoring that introduced a null assignment.","solutions":["Pass a non-empty header name such as \"X-Client-Cert\".","If the value comes from config, ensure the config key is populated and not blank.","Guard the call site with a null/empty check before constructing the transform."],"exampleFix":"// before\nnew RequestHeaderClientCertTransform(headerName /* null */);\n// after\nnew RequestHeaderClientCertTransform(\n    string.IsNullOrEmpty(headerName) ? \"X-Client-Cert\" : headerName);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(headerName))\n    throw new InvalidOperationException(\"headerName must be set before creating the transform.\");\nvar transform = new RequestHeaderClientCertTransform(headerName);","typeGuard":"static bool IsValidHeaderName(string? name)\n    => !string.IsNullOrWhiteSpace(name);","tryCatchPattern":null,"preventionTips":["Always initialise header-name variables from a known non-empty source.","When adding transforms via AddTransform, validate inputs at the top of the callback.","Prefer the built-in fluent extension methods (AddClientCertHeader) which document the expected values."],"tags":["yarp","transforms","argument-validation","headers"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}