caddyserver/caddy · error
unexpected proxy protocol version
Error message
unexpected proxy protocol version
What it means
After a successful proxy-protocol info lookup, the transport switches on the configured `proxy_protocol` version and only accepts "v1" or "v2". Any other value falls to default and returns this error from the dialer. In practice only reachable via hand-written JSON, since the Caddyfile adapter validates the token.
Source
Thrown at modules/caddyhttp/reverseproxy/httptransport.go:312
// 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{
IP: net.IPv4zero,
}
case proxyProtocolInfo.AddrPort.Addr().Is6():
destAddr = &net.TCPAddr{
IP: net.IPv6zero,
}
default:
return nil, fmt.Errorf("unexpected remote addr type in proxy protocol info")
}View on GitHub (pinned to 50e54ee279)
Solutions
- Set proxy_protocol to exactly "v1" or "v2" (string with the leading v)
- Prefer authoring in Caddyfile and adapting with `caddy adapt` so invalid tokens are caught at adapt time
Example fix
// JSON before
"transport": {"protocol": "http", "proxy_protocol": "2"}
// JSON after
"transport": {"protocol": "http", "proxy_protocol": "v2"} Defensive patterns
Strategy: validation
Validate before calling
switch h.ProxyProtocol {
case "", "v1", "v2":
default:
return fmt.Errorf("proxy_protocol must be v1 or v2, got %q", h.ProxyProtocol)
} Prevention
- Generate JSON from the Caddyfile (`caddy adapt`) instead of hand-writing it
- Unit-test config templates against the accepted enum
When it happens
Trigger: JSON config with transport.proxy_protocol set to something like "v3", "2", or an empty-but-present value; custom config generators that emit the raw field without validating it.
Common situations: Programmatic config generation or hand-edited JSON where the Caddyfile's syntax validation is bypassed.
Related errors
- %s is %w
- header-up %d: invalid format "%s" (expecting "Field: value")
- header-down %d: invalid format "%s" (expecting "Field: value
- cannot define both 'exclude' and 'include' lists at the same
- expect_body: compiling regular expression: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/347d5669d5d1cab4.
Report an issue: GitHub.