{"record":{"id":"f62877aea3756bc3","repo":"cloudflare/cloudflared","slug":"header-key-s-malformed","errorCode":null,"errorMessage":"header Key: %s malformed","messagePattern":"header Key: (.+?) malformed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"connection/quic_connection.go","lineNumber":364,"sourceCode":") (*tracing.TracedHTTPRequest, error) {\n\tmetadata := connectRequest.MetadataMap()\n\tdest := connectRequest.Dest\n\tmethod := metadata[HTTPMethodKey]\n\thost := metadata[HTTPHostKey]\n\tisWebsocket := connectRequest.Type == pogs.ConnectionTypeWebsocket\n\n\treq, err := http.NewRequestWithContext(ctx, method, dest, body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.Host = host\n\tfor _, metadata := range connectRequest.Metadata {\n\t\tif strings.Contains(metadata.Key, HTTPHeaderKey) {\n\t\t\t// metadata.Key is off the format httpHeaderKey:<HTTPHeader>\n\t\t\thttpHeaderKey := strings.Split(metadata.Key, \":\")\n\t\t\tif len(httpHeaderKey) != 2 {\n\t\t\t\treturn nil, fmt.Errorf(\"header Key: %s malformed\", metadata.Key)\n\t\t\t}\n\t\t\treq.Header.Add(httpHeaderKey[1], metadata.Val)\n\t\t}\n\t}\n\t// Go's http.Client automatically sends chunked request body if this value is not set on the\n\t// *http.Request struct regardless of header:\n\t// https://go.googlesource.com/go/+/go1.8rc2/src/net/http/transfer.go#154.\n\tif err := setContentLength(req); err != nil {\n\t\treturn nil, fmt.Errorf(\"Error setting content-length: %w\", err)\n\t}\n\n\t// Go's client defaults to chunked encoding after a 200ms delay if the following cases are true:\n\t//   * the request body blocks\n\t//   * the content length is not set (or set to -1)\n\t//   * the method doesn't usually have a body (GET, HEAD, DELETE, ...)\n\t//   * there is no transfer-encoding=chunked already set.\n\t// So, if transfer cannot be chunked and content length is 0, we dont set a request body.\n\tif !isWebsocket && !isTransferEncodingChunked(req) && req.ContentLength == 0 {","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/connection/quic_connection.go#L346-L382","documentation":"buildHTTPRequest translates edge request metadata into HTTP headers on the outgoing origin request. HTTP header metadata is encoded as metadata keys of the form \"httpHeaderKey:<HTTPHeader>\"; when such a key does not split into exactly two colon-separated parts, the code rejects it with \"header Key: %s malformed\". This prevents silently dropping or mis-assigning header values on proxied requests.","triggerScenarios":"A connect request carries metadata whose key contains \"httpHeaderKey\" but is not of the exact form \"httpHeaderKey:HeaderName\" — e.g. \"httpHeaderKey\" with no colon, or \"httpHeaderKey:X:Y\" with an extra colon.","commonSituations":"Misconfigured upstream clients injecting header pass-through metadata; edge configs or ingress rules authored with the wrong delimiter; typos in custom header propagation rules.","solutions":["Fix the metadata key to have exactly one colon: \"httpHeaderKey:My-Header\"","Remove extra colons from the header name (header names cannot contain ':')","If you control the sender, validate metadata keys before sending","Check which component emits the metadata (edge config or client) and correct it there"],"exampleFix":"// before\nhttpHeaderKey: \"X-Custom:Header\"\n// after\nhttpHeaderKey: \"X-Custom-Header\"","handlingStrategy":"validation","validationCode":"// validate httpHeaderKey metadata before sending\nkey := metadata.Key\nif strings.Contains(key, \"httpHeaderKey\") {\n\tparts := strings.Split(key, \":\")\n\tif len(parts) != 2 || parts[1] == \"\" {\n\t\treturn fmt.Errorf(\"invalid httpHeaderKey metadata: %q\", key)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always format metadata keys as \"httpHeaderKey:Header-Name\" with exactly one colon","Avoid header names containing ':' characters","Add a pre-send validation pass over request metadata in the client"],"tags":["go","http","headers","quic"],"backgroundTag":"invalid-argument-format","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}