{"record":{"id":"39d69b9a564598e2","repo":"caddyserver/caddy","slug":"cannot-use-copy-response-headers-outside-of-reve","errorCode":null,"errorMessage":"cannot use 'copy_response_headers' outside of reverse_proxy's handle_response routes","messagePattern":"cannot use 'copy_response_headers' outside of reverse_proxy's handle_response routes","errorType":"http","errorClass":"caddyhttp.Error","httpStatus":500,"severity":"error","filePath":"modules/caddyhttp/reverseproxy/copyresponse.go","lineNumber":151,"sourceCode":"\t// Optimize the exclude list by converting it to a map\n\tif len(h.Exclude) > 0 {\n\t\th.excludeMap = map[string]struct{}{}\n\t}\n\tfor _, field := range h.Exclude {\n\t\th.excludeMap[http.CanonicalHeaderKey(field)] = struct{}{}\n\t}\n\n\treturn nil\n}\n\n// ServeHTTP implements the Handler interface.\nfunc (h CopyResponseHeadersHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next caddyhttp.Handler) error {\n\thrc, ok := req.Context().Value(proxyHandleResponseContextCtxKey).(*handleResponseContext)\n\n\t// don't allow this to be used outside of handle_response routes\n\tif !ok {\n\t\treturn caddyhttp.Error(http.StatusInternalServerError,\n\t\t\tfmt.Errorf(\"cannot use 'copy_response_headers' outside of reverse_proxy's handle_response routes\"))\n\t}\n\n\tfor field, values := range hrc.response.Header {\n\t\t// Check the include list first, skip\n\t\t// the header if it's _not_ in this list.\n\t\tif len(h.includeMap) > 0 {\n\t\t\tif _, ok := h.includeMap[field]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Then, check the exclude list, skip\n\t\t// the header if it _is_ in this list.\n\t\tif len(h.excludeMap) > 0 {\n\t\t\tif _, ok := h.excludeMap[field]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/reverseproxy/copyresponse.go#L133-L169","documentation":"`copy_response_headers` reads the upstream response from the request context key `proxyHandleResponseContextCtxKey`, which is only set inside reverse_proxy's handle_response routes. Used elsewhere, the type assertion fails and the request gets a 500 with this message.","triggerScenarios":"Placing copy_response_headers in a regular route (not inside reverse_proxy's handle_response), or dispatching requests to CopyResponseHeadersHandler.ServeHTTP directly without the reverse_proxy response context.","commonSituations":"Refactoring a Caddyfile and moving the copy_response_headers block into the main route; assuming it works like the generic `header` directive.","solutions":["Move copy_response_headers into a handle_response block within reverse_proxy","Use the plain `header` directive with deletion/setting if you want to manipulate headers outside handle_response","Validate the config path: caddy adapt --config to inspect where the handler ended up in JSON"],"exampleFix":"# before\nexample.com {\n\treverse_proxy localhost:9000 {\n\t\thandle_response {\n\t\t\tcopy_response\n\t\t}\n\t}\n\tcopy_response_headers {\n\t\tinclude Content-Type\n\t}\n}\n# after\nexample.com {\n\treverse_proxy localhost:9000 {\n\t\thandle_response {\n\t\t\tcopy_response\n\t\t\tcopy_response_headers {\n\t\t\t\tinclude Content-Type\n\t\t\t}\n\t\t}\n\t}\n}","handlingStrategy":"validation","validationCode":"// Guard: copy_response_handlers must sit inside handle_response\nfor _, h := range route.Handlers {\n\tif h.ID == \"http.handlers.copy_response_headers\" && !route.IsHandleResponse {\n\t\treturn errors.New(\"copy_response_headers outside handle_response\")\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the Caddyfile form so handle_response structure is enforced by the adapter","Run `caddy adapt` and inspect the JSON nesting of copy_* handlers before deploy"],"tags":["reverse-proxy","caddyfile","handle-response","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}