fatedier/frp · error
failed to write proxy protocol header: %v
Error message
failed to write proxy protocol header: %v
What it means
BuildProxyProtocolHeader serializes a proxy-protocol header struct (v1 or v2, built by HeaderProxyFromAddrs) into a bytes.Buffer via WriteTo. Because the destination is an in-memory bytes.Buffer, WriteTo only fails if the header object itself refuses to encode — e.g. an address family that the proxy protocol cannot represent. Real network failures cannot occur here.
Source
Thrown at pkg/util/net/proxyprotocol.go:42
func BuildProxyProtocolHeaderStruct(srcAddr, dstAddr net.Addr, version string) *pp.Header {
var versionByte byte
if version == "v1" {
versionByte = 1
} else {
versionByte = 2 // default to v2
}
return pp.HeaderProxyFromAddrs(versionByte, srcAddr, dstAddr)
}
func BuildProxyProtocolHeader(srcAddr, dstAddr net.Addr, version string) ([]byte, error) {
h := BuildProxyProtocolHeaderStruct(srcAddr, dstAddr, version)
// Convert header to bytes using a buffer
var buf bytes.Buffer
_, err := h.WriteTo(&buf)
if err != nil {
return nil, fmt.Errorf("failed to write proxy protocol header: %v", err)
}
return buf.Bytes(), nil
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Pass plain *net.TCPAddr (or UDP/Unix addrs) as srcAddr/dstAddr.
- If you wrap conns, make sure LocalAddr/RemoteAddr still return standard address types.
- On error, fall back to omitting the proxy protocol header for that connection.
Example fix
// before
hdr, err := netpkg.BuildProxyProtocolHeader(customAddr{network: "weird"}, dst, "v2")
// after
hdr, err := netpkg.BuildProxyProtocolHeader(conn.RemoteAddr().(*net.TCPAddr), conn.LocalAddr().(*net.TCPAddr), "v2") Defensive patterns
Strategy: fallback
Validate before calling
// ensure addresses are proxy-protocol representable before building the header
func proxyProtocolRepresentable(addr net.Addr) bool {
switch addr.(type) {
case *net.TCPAddr, *net.UDPAddr, *net.UnixAddr:
return true
}
return false
} Try / catch
header, err := netpkg.BuildProxyProtocolHeader(srcAddr, dstAddr, version)
if err != nil {
// degrade gracefully: serve the connection without PROXY info
log.Warnf("proxy protocol header build failed: %v", err)
header = nil
} Prevention
- Pass standard TCP/UDP/Unix address types; never bespoke net.Addr implementations.
- Keep conn wrappers transparent: LocalAddr/RemoteAddr must return the underlying standard types.
- Treat failure as 'omit header' rather than killing the connection.
When it happens
Trigger: srcAddr/dstAddr with a network type the proxy protocol library cannot map to a v1/v2 family (an exotic net.Addr implementation rather than TCPAddr/UDPAddr/UnixAddr), since v1 text encoding or v2 binary encoding of unsupported families fails.
Common situations: Custom net.Conn wrappers whose LocalAddr/RemoteAddr return bespoke address types; essentially never with standard TCP conns.
Related errors
- loginRespMsg.Error
- send ${op} request to plugin error
- create control crypto read writer: %w
- unexpected frame type %d, want %d
- login to the server failed: %v. With loginFailExit enabled,
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/c8adeaa22feac1e7.
Report an issue: GitHub.