nats-io/nats-server · error

%w: v1 line too long

Error message

%w: v1 line too long

What it means

The server detected that the PROXY protocol v1 header line exceeded the protocol maximum of 107 bytes (including CRLF) without encountering a terminating CRLF. Per the PROXY protocol spec, a v1 header must fit in 107 bytes, so a longer line means the sender is not a conforming proxy or the stream is corrupted. The server aborts the connection with an error wrapping errProxyProtoInvalid.

Source

Thrown at server/client_proxyproto.go:168

		if err != nil {
			return nil, nil, fmt.Errorf("failed to read v1 line: %w", err)
		}

		line = buf[:len(line)+n]

		// Look for CRLF in what we've read so far
		for i := 0; i < len(line)-1; i++ {
			if line[i] == '\r' && line[i+1] == '\n' {
				// Found CRLF - keep any over-read bytes for the client parser.
				remaining = append(remaining, line[i+2:]...)
				line = line[:i]
				goto foundCRLF
			}
		}
	}

	// Exceeded max length without finding CRLF
	return nil, nil, fmt.Errorf("%w: v1 line too long", errProxyProtoInvalid)

foundCRLF:
	// Get parts from the protocol
	parts := strings.Fields(string(line))

	// Validate format
	if len(parts) < 1 {
		return nil, nil, fmt.Errorf("%w: invalid v1 format", errProxyProtoInvalid)
	}

	// Handle UNKNOWN (health check, like v2 LOCAL)
	if parts[0] == proxyProtoV1Unknown {
		return nil, remaining, nil
	}

	// Must have exactly 5 parts: protocol, src-ip, dst-ip, src-port, dst-port
	if len(parts) != 5 {
		return nil, nil, fmt.Errorf("%w: invalid v1 format", errProxyProtoInvalid)

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Verify the upstream proxy actually emits conforming PROXY v1 headers (max 107 bytes ending in CRLF)
  2. Check the load balancer's proxy-protocol configuration (e.g. HAProxy 'send-proxy' vs 'send-proxy-v2') and fix version mismatch
  3. Ensure no non-PROXY-protocol clients are connecting directly to the proxy-protocol port
  4. Capture the incoming bytes with tcpdump/ngrep to identify the offending sender

Example fix

// before: proxy sends oversized header
PROXY TCP4 2001:0db8:85a3:0000:0000:8a2e:0370:7334-with-garbage-padding... (no CRLF within 107 bytes)
// after: proxy emits conforming header
PROXY TCP4 192.0.2.1 198.51.100.7 35646 4222\r\n
Defensive patterns

Strategy: validation

Validate before calling

// Before emitting a PROXY v1 header from your proxy/client:
header := fmt.Sprintf("PROXY %s %s %s %d %d\r\n", proto, srcIP, dstIP, srcPort, dstPort)
if len(header) > 107 {
    return errors.New("PROXY v1 header exceeds 107-byte limit")
}
conn.Write([]byte(header))

Type guard

func isValidV1HeaderLine(line string) bool {
    return len(line) <= 107 && strings.HasSuffix(line, "\r\n")
}

Try / catch

addr, _, err := readProxyProtoHeader(conn)
if err != nil {
    if errors.Is(err, errProxyProtoInvalid) {
        log.Printf("malformed PROXY header (line too long): %v", err)
        conn.Close() // drop non-conforming sender
        return
    }
    return err
}

Prevention

When it happens

Trigger: A client connects to a PROXY-protocol-enabled listener and sends 'PROXY ' followed by more than 101 additional bytes (107 - 6 already read) without a '\r\n' terminator; e.g. a non-proxy client sending arbitrary text, or a proxy emitting a malformed over-long header.

Common situations: Misconfigured load balancer (HAProxy/nginx) sending non-standard headers; a plain NATS client accidentally pointed at a proxy-protocol port; a health-check or port scanner writing long garbage lines; corrupted TCP stream from a broken intermediary.

Related errors


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