caddyserver/caddy · error
failed to get proxy protocol info from context
Error message
failed to get proxy protocol info from context
What it means
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.
Source
Thrown at modules/caddyhttp/reverseproxy/httptransport.go:303
if dialInfo, ok := GetDialInfo(ctx); ok {
if caddyhttp.GetVar(ctx, proxyVarKey) == nil || strings.HasPrefix(dialInfo.Network, "unix") {
network = dialInfo.Network
address = dialInfo.Address
}
}
conn, err := dialer.DialContext(ctx, network, address)
if err != nil {
// identify this error as one that occurred during
// dialing, which can be important when trying to
// decide whether to retry a request
return nil, DialError{err}
}
if h.ProxyProtocol != "" {
proxyProtocolInfo, ok := caddyhttp.GetVar(ctx, proxyProtocolInfoVarKey).(ProxyProtocolInfo)
if !ok {
return nil, fmt.Errorf("failed to get proxy protocol info from context")
}
var proxyv byte
switch h.ProxyProtocol {
case "v1":
proxyv = 1
case "v2":
proxyv = 2
default:
return nil, fmt.Errorf("unexpected proxy protocol version")
}
// The src and dst have to be of the same address family. As we don't know the original
// dst address (it's kind of impossible to know) and this address is generally of very
// little interest, we just set it to all zeros.
var destAddr net.Addr
switch {
case proxyProtocolInfo.AddrPort.Addr().Is4():
destAddr = &net.TCPAddr{View on GitHub (pinned to 50e54ee279)
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
Example fix
# before
example.com {
reverse_proxy localhost:9000 {
transport http {
proxy_protocol v2
}
}
}
# after
example.com {
listener_wrappers {
proxy_protocol
}
reverse_proxy localhost:9000 {
transport http {
proxy_protocol v2
}
}
} Defensive patterns
Strategy: validation
Validate before calling
// Config guard: transport proxy_protocol requires the listener wrapper
if site.HasTransportProxyProtocol() && !site.HasListenerWrapper("proxy_protocol") {
return errors.New("add listener_wrappers { proxy_protocol } to accept PROXY protocol first")
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- listening on %s: %v
- network '%s' cannot handle HTTP/1 or HTTP/2 connections
- local_address must be a single address, not a port range
- local_address must be a TCP address, not a UDP address
- unsupported network
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/5f73b7717b2f9622.
Report an issue: GitHub.