{"record":{"id":"b5de096bc43412a9","repo":"cloudflare/cloudflared","slug":"error-writing-response-header","errorCode":null,"errorMessage":"Error writing response header","messagePattern":"Error writing response header","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/proxy.go","lineNumber":243,"sourceCode":"\t\t}\n\t\treturn errors.Wrap(err, \"Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared\")\n\t}\n\n\ttracing.EndWithStatusCode(ttfbSpan, resp.StatusCode)\n\tdefer func() { _ = resp.Body.Close() }()\n\n\theaders := make(http.Header, len(resp.Header))\n\t// copy headers\n\tfor k, v := range resp.Header {\n\t\theaders[k] = v\n\t}\n\n\t// Add spans to response header (if available)\n\ttr.AddSpans(headers)\n\n\terr = w.WriteRespHeaders(resp.StatusCode, headers)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"Error writing response header\")\n\t}\n\n\tif resp.StatusCode == http.StatusSwitchingProtocols {\n\t\trwc, ok := resp.Body.(io.ReadWriteCloser)\n\t\tif !ok {\n\t\t\treturn errors.New(\"internal error: unsupported connection type\")\n\t\t}\n\t\tdefer func() { _ = rwc.Close() }()\n\n\t\teyeballStream := &bidirectionalStream{\n\t\t\twriter: w,\n\t\t\treader: tr.Body,\n\t\t}\n\n\t\tstream.Pipe(eyeballStream, rwc, logger)\n\t\treturn nil\n\t}\n","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/proxy/proxy.go#L225-L261","documentation":"After a successful origin response, proxyHTTPRequest writes the status code and origin headers back to the edge via w.WriteRespHeaders. If that write fails, it is wrapped as 'Error writing response header'. This indicates the downstream connection to Cloudflare's edge (or the client) broke while relaying the response headers, not an origin problem.","triggerScenarios":"w.WriteRespHeaders(resp.StatusCode, headers) returns an error — typically because the underlying stream/connection to the edge is closed, reset, or the headers cannot be encoded on the transport.","commonSituations":"Client disconnected or page reload before response headers were sent; edge connection dropped due to network interruption; invalid/duplicate hop-by-hop headers from the origin causing encoding failure on the tunnel transport.","solutions":["Check whether the end client actually cancelled/aborted the request; this is usually benign client disconnect noise.","Verify network stability between cloudflared and Cloudflare edge (look for repeated reconnects in the log).","Inspect origin response headers for invalid values (control characters, oversized headers) that fail transport encoding.","Retry the request; a one-off error during an edge reconnect is transient."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// validate origin headers before relay: reject control chars\nfor k, vs := range resp.Header {\n    for _, v := range vs {\n        if strings.ContainsAny(v, \"\\r\\n\\x00\") {\n            return fmt.Errorf(\"invalid header value for %s\", k)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := w.WriteRespHeaders(resp.StatusCode, headers); err != nil {\n    // log at debug: usually client/edge disconnect, not actionable\n    log.Debug().Err(err).Msg(\"client disconnected before headers written\")\n    return err\n}","preventionTips":["Treat this as transient: most occurrences are client aborts or edge reconnects.","Sanitize origin response headers if the origin is third-party or misconfigured.","Monitor tunnel-to-edge connection stability metrics.","Avoid oversized response headers from the origin (e.g. giant Set-Cookie chains)."],"tags":["network","proxy","http-headers","connection-reset"],"backgroundTag":"broken-pipe","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"}