nats-io/nats-server · warning

failed to discard UNSPEC address address data: %w

Error message

failed to discard UNSPEC address address data: %w

What it means

When family is UNSPEC (0x0) with a PROXY command, the address payload carries no usable address, so the library simply discards addrLen bytes from the connection and returns nil. This error wraps any I/O failure while discarding those bytes — usually the peer closing or timing out before all advertised bytes arrive.

Source

Thrown at server/client_proxyproto.go:371

	// Validate protocol (we only support STREAM/TCP)
	if protocol != proxyProtoProtoStream {
		return nil, fmt.Errorf("%w: only STREAM protocol supported", errProxyProtoUnsupported)
	}

	// Parse address data based on family
	var addr *proxyProtoAddr
	var err error
	switch family {
	case proxyProtoFamilyInet:
		addr, err = parseIPv4Addr(conn, addrLen)
	case proxyProtoFamilyInet6:
		addr, err = parseIPv6Addr(conn, addrLen)
	case proxyProtoFamilyUnspec:
		// UNSPEC family with PROXY command is valid but rare
		// Just skip the address data
		if addrLen > 0 {
			if _, err := io.CopyN(io.Discard, conn, int64(addrLen)); err != nil {
				return nil, fmt.Errorf("failed to discard UNSPEC address address data: %w", err)
			}
		}
		return nil, nil
	default:
		return nil, fmt.Errorf("%w: unsupported address family 0x%02x", errProxyProtoUnsupported, family)
	}
	return addr, err
}

// parseIPv4Addr parses IPv4 address data from PROXY protocol header
func parseIPv4Addr(conn net.Conn, addrLen uint16) (*proxyProtoAddr, error) {
	// IPv4: 4 (src IP) + 4 (dst IP) + 2 (src port) + 2 (dst port) = 12 bytes minimum
	if addrLen < proxyProtoAddrSizeIPv4 {
		return nil, fmt.Errorf("IPv4 address data too short: %d bytes", addrLen)
	}
	addrData := make([]byte, addrLen)
	if _, err := io.ReadFull(conn, addrData); err != nil {
		return nil, fmt.Errorf("failed to read IPv4 address data: %w", err)

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Inspect the wrapped error: unexpected EOF indicates the sender advertised more bytes than it sent
  2. Fix the sender to set addrLen=0 for UNSPEC family, or send the full advertised payload
  3. Retry the connection if transient (deadline exceeded / connection reset)
  4. Bump the read deadline if the sender is merely slow

Example fix

// before: UNSPEC header claiming 16 bytes, then close
write(sig+header); conn.Close()
// after: either addrLen=0 or write the full 16 payload bytes
header addrLen=0x0000; write(sig+header)
Defensive patterns

Strategy: try-catch

Try / catch

addr, err := readProxyProtoHeader(conn)
if err != nil && strings.Contains(err.Error(), "failed to discard UNSPEC address address data") {
    if errors.Is(err, io.ErrUnexpectedEOF) {
        return errRetryable // sender truncated the payload
    }
    return err
}

Prevention

When it happens

Trigger: Peer declares UNSPEC family with addrLen>0 but delivers fewer bytes than advertised, or the connection hits the read deadline / EOF / reset while io.CopyN drains the payload.

Common situations: Truncated headers from buggy or restarted proxies; health-check style senders using UNSPEC with a nonzero length then disconnecting; flaky network dropping mid-payload.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/5918bae9f625f12c. Report an issue: GitHub.