nats-io/nats-server · error
failed to read v1 line: %w
Error message
failed to read v1 line: %w
What it means
After detecting PROXY protocol v1, the server reads the rest of the header line up to CRLF; conn.Read failed mid-read (timeout, reset, EOF), so the v1 header could not be completed and the wrapped I/O error is returned.
Source
Thrown at server/client_proxyproto.go:151
// readProxyProtoV1Header parses PROXY protocol v1 text format.
// Expects the "PROXY " prefix (6 bytes) to have already been consumed.
// Returns any bytes that were read past the trailing CRLF so the caller can
// replay them into the next protocol layer.
func readProxyProtoV1Header(conn net.Conn) (*proxyProtoAddr, []byte, error) {
// Read rest of line (max 107 bytes total, already read 6)
maxRemaining := proxyProtoV1MaxLineLen - 6
// Read up to maxRemaining bytes at once (more efficient than byte-by-byte)
buf := make([]byte, maxRemaining)
var line []byte
var remaining []byte
for len(line) < maxRemaining {
// Read available data
n, err := conn.Read(buf[len(line):])
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)
View on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the upstream proxy to send the complete single-line PROXY v1 header terminated by CRLF
- Check proxy health/stability and network path (resets, timeouts) between proxy and server
- Verify the proxy version supports PROXY protocol v1 and its header fits on one line under maxRemaining
- Reproduce with packet capture on the server port to see the truncated header bytes
Example fix
// before (truncated header) PROXY TCP4 10.0.0.1 // after (complete v1 line with CRLF) PROXY TCP4 10.0.0.1 10.0.0.2 50000 4222\r\n
Defensive patterns
Strategy: fallback
Validate before calling
// sender side: ensure full line + CRLF is written before flushing
header := fmt.Sprintf("PROXY TCP4 %s %s %d %d\r\n", srcIP, dstIP, srcPort, dstPort)
if n, err := conn.Write([]byte(header)); err != nil || n != len(header) {
return fmt.Errorf("short proxy header write: %d/%d", n, len(header))
} Try / catch
header, err := readProxyProtoHeader(conn)
if err != nil {
// inspect wrapped cause; retry or fall back to direct connection
return fmt.Errorf("proxy header failed: %w", err)
} Prevention
- Write the entire PROXY v1 line in a single buffered write ending with CRLF
- Keep the proxy-server network path stable; monitor for resets
- Ensure the header line length stays under the server's maxRemaining limit
- Test load balancer PROXY protocol configuration with a packet capture
When it happens
Trigger: A PROXY v1 sender writes fewer than 6 bytes then stalls, is killed, or the connection is reset before the full `PROXY ... CRLF` line arrives; also triggered when the line exceeds maxRemaining without CRLF causing continued reads to fail.
Common situations: Misconfigured load balancer sending a truncated PROXY v1 line, flaky network between proxy and NATS server, proxy crashed mid-handshake, MTU/buffer issues truncating the header.
Related errors
- failed to read protocol version: %w
- %w: v1 line too long
- failed to read v2 signature: %w
- %w: invalid v1 format
- %w: invalid address
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/4c298d24a6fb9997.
Report an issue: GitHub.