{"record":{"id":"5f73b7717b2f9622","repo":"caddyserver/caddy","slug":"failed-to-get-proxy-protocol-info-from-context","errorCode":null,"errorMessage":"failed to get proxy protocol info from context","messagePattern":"failed to get proxy protocol info from context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/reverseproxy/httptransport.go","lineNumber":303,"sourceCode":"\t\tif dialInfo, ok := GetDialInfo(ctx); ok {\n\t\t\tif caddyhttp.GetVar(ctx, proxyVarKey) == nil || strings.HasPrefix(dialInfo.Network, \"unix\") {\n\t\t\t\tnetwork = dialInfo.Network\n\t\t\t\taddress = dialInfo.Address\n\t\t\t}\n\t\t}\n\n\t\tconn, err := dialer.DialContext(ctx, network, address)\n\t\tif err != nil {\n\t\t\t// identify this error as one that occurred during\n\t\t\t// dialing, which can be important when trying to\n\t\t\t// decide whether to retry a request\n\t\t\treturn nil, DialError{err}\n\t\t}\n\n\t\tif h.ProxyProtocol != \"\" {\n\t\t\tproxyProtocolInfo, ok := caddyhttp.GetVar(ctx, proxyProtocolInfoVarKey).(ProxyProtocolInfo)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get proxy protocol info from context\")\n\t\t\t}\n\t\t\tvar proxyv byte\n\t\t\tswitch h.ProxyProtocol {\n\t\t\tcase \"v1\":\n\t\t\t\tproxyv = 1\n\t\t\tcase \"v2\":\n\t\t\t\tproxyv = 2\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"unexpected proxy protocol version\")\n\t\t\t}\n\n\t\t\t// The src and dst have to be of the same address family. As we don't know the original\n\t\t\t// dst address (it's kind of impossible to know) and this address is generally of very\n\t\t\t// little interest, we just set it to all zeros.\n\t\t\tvar destAddr net.Addr\n\t\t\tswitch {\n\t\t\tcase proxyProtocolInfo.AddrPort.Addr().Is4():\n\t\t\t\tdestAddr = &net.TCPAddr{","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/reverseproxy/httptransport.go#L285-L321","documentation":"When `proxy_protocol` is set on the HTTP transport, the dialer expects the original client address to have been stored in the request context variable `proxyProtocolInfoVarKey` (populated by the listener's proxy_protocol wrapper). If the type assertion fails, the custom dialer returns this error and the request fails.","triggerScenarios":"Enabling `transport http { proxy_protocol v2 }` on a site whose server listener does NOT have the `listener_wrappers { proxy_protocol }` wrapper, so no PROXY-protocol info ever enters the context. Also dispatching synthesized requests that bypass the listener.","commonSituations":"Adding proxy_protocol to the transport to forward client info to an upstream (like an LB or Cloudflare-origin setup) while forgetting that the server must first accept PROXY protocol on the inbound side.","solutions":["Add listener_wrappers { proxy_protocol } to the same server block so the inbound connection is decoded and client info is captured","Verify ordering: listener_wrappers must come before routes in the Caddyfile site block","If the client does not actually send PROXY protocol headers, either require it at the listener or remove proxy_protocol from the transport"],"exampleFix":"# before\nexample.com {\n\treverse_proxy localhost:9000 {\n\t\ttransport http {\n\t\t\tproxy_protocol v2\n\t\t}\n\t}\n}\n# after\nexample.com {\n\tlistener_wrappers {\n\t\tproxy_protocol\n\t}\n\treverse_proxy localhost:9000 {\n\t\ttransport http {\n\t\t\tproxy_protocol v2\n\t\t}\n\t}\n}","handlingStrategy":"validation","validationCode":"// Config guard: transport proxy_protocol requires the listener wrapper\nif site.HasTransportProxyProtocol() && !site.HasListenerWrapper(\"proxy_protocol\") {\n\treturn errors.New(\"add listener_wrappers { proxy_protocol } to accept PROXY protocol first\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair transport proxy_protocol with listener_wrappers { proxy_protocol } in the same site","Ensure the downstream peer (LB/CDN) actually sends PROXY protocol headers"],"tags":["reverse-proxy","proxy-protocol","network","listener"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}