{"record":{"id":"51b10ff84e9febad","repo":"caddyserver/caddy","slug":"cannot-use-copy-response-outside-of-reverse-prox","errorCode":null,"errorMessage":"cannot use 'copy_response' outside of reverse_proxy's handle_response routes","messagePattern":"cannot use 'copy_response' outside of reverse_proxy's handle_response routes","errorType":"http","errorClass":"caddyhttp.Error","httpStatus":500,"severity":"error","filePath":"modules/caddyhttp/reverseproxy/copyresponse.go","lineNumber":65,"sourceCode":"\t\tNew: func() caddy.Module { return new(CopyResponseHandler) },\n\t}\n}\n\n// Provision ensures that h is set up properly before use.\nfunc (h *CopyResponseHandler) Provision(ctx caddy.Context) error {\n\th.ctx = ctx\n\treturn nil\n}\n\n// ServeHTTP implements the Handler interface.\nfunc (h CopyResponseHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, _ caddyhttp.Handler) error {\n\trepl := req.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)\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' outside of reverse_proxy's handle_response routes\"))\n\t}\n\n\t// allow a custom status code to be written; otherwise the\n\t// status code from the upstream response is written\n\tif codeStr := h.StatusCode.String(); codeStr != \"\" {\n\t\tintVal, err := strconv.Atoi(repl.ReplaceAll(codeStr, \"\"))\n\t\tif err != nil {\n\t\t\treturn caddyhttp.Error(http.StatusInternalServerError, err)\n\t\t}\n\t\thrc.response.StatusCode = intVal\n\t}\n\n\t// make sure the reverse_proxy handler doesn't try to call\n\t// finalizeResponse again after we've already done it here.\n\thrc.isFinalized = true\n\n\t// write the response\n\treturn hrc.handler.finalizeResponse(rw, req, hrc.response, repl, hrc.start, hrc.logger)","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/reverseproxy/copyresponse.go#L47-L83","documentation":"`copy_response` is a handler that only works inside a `handle_response` route of `reverse_proxy`, because it relies on the upstream response stored in the request context under `proxyHandleResponseContextCtxKey`. When that context value is absent, Caddy returns HTTP 500 with this message.","triggerScenarios":"Configuring `copy_response` as a top-level handler in a normal `handle` route, or inside `reverse_proxy` outside a `handle_response` block. Also programmatically invoking CopyResponseHandler.ServeHTTP on requests that never traversed reverse_proxy's handle_response machinery.","commonSituations":"Copy-pasting a handle_response fragment into the main route body, or restructuring a Caddyfile and accidentally moving copy_response outside its handle_response block.","solutions":["Move copy_response inside a handle_response block of reverse_proxy","Ensure the route order is: reverse_proxy with handle_response, and copy_response within that block","If using JSON config, verify the handler appears only under reverse_proxy's handle_response routes"],"exampleFix":"// Caddyfile before\nexample.com {\n\tcopy_response\n\treverse_proxy localhost:9000\n}\n// Caddyfile after\nexample.com {\n\treverse_proxy localhost:9000 {\n\t\t@error status 500\n\t\thandle_response @error {\n\t\t\tcopy_response\n\t\t}\n\t}\n}","handlingStrategy":"validation","validationCode":"// JSON config guard: copy_response may only appear under\n// reverse_proxy.handlers[].handle_response\nfunc containsOnlyInHandleResponse(cfg *Config) bool {\n\tfor _, r := range cfg.Routes {\n\t\tif r.HandlerID == \"http.handlers.copy_response\" && !r.WithinHandleResponse {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Author handle_response trees in the Caddyfile, not raw JSON — the adapter places handlers correctly","Lint adapted JSON for copy_response handlers not nested under handle_response routes","Run `caddy validate --config` before deploy to catch structural mistakes early"],"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"}