OpenNHP/opennhp · error

packet too large

Error message

packet too large

What it means

handleRelay responds with HTTP 400 'packet too large' when the body exceeds maxPacketSize bytes. The read is capped at maxPacketSize+1 so anything longer than the limit is detected without buffering an unbounded payload, protecting relay memory from oversized uploads.

Solutions

  1. Reduce the inner packet size on the client to fit within maxPacketSize
  2. Check for version skew: client and relay must agree on the NHP packet size limit
  3. Verify the client is sending the compact NHP packet, not a wrapped/base64 or debug-encoded form

Example fix

// before
body := buildHugePayload() // > maxPacketSize
// after
if len(body) > maxPacketSize { return fmt.Errorf("packet %d exceeds limit %d", len(body), maxPacketSize) }
req, _ := http.NewRequest("POST", relayURL, bytes.NewReader(body))
Defensive patterns

Strategy: validation

Validate before calling

if len(packet) > maxPacketSize {
    return fmt.Errorf("packet is %d bytes, exceeds relay limit %d", len(packet), maxPacketSize)
}

Try / catch

if resp.StatusCode == http.StatusBadRequest {
    b, _ := io.ReadAll(resp.Body)
    if strings.Contains(string(b), "packet too large") {
        return fmt.Errorf("oversize packet %d bytes; compress or split before sending", len(packet))
    }
}

Prevention

When it happens

Trigger: POSTing a body larger than maxPacketSize to the relay endpoint, as exercised by TestRouting_OversizeBodyReturns400.

Common situations: Client serializing a malformed or bloated packet; a misconfigured client using a packet format/version with a larger header; generic HTTP clients reusing the endpoint to upload unrelated data.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/39ea5795d7363e41. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/relay/relay.go:969

		http.Error(w, errMsg, status)
		return
	}

	// Read inner NHP packet from request body. Cap at maxPacketSize+1 so we
	// can reject oversize bodies without pulling an unbounded amount into
	// memory. A single r.Body.Read() is not guaranteed to return the full
	// payload; io.ReadAll drains until EOF.
	innerPacket, err := io.ReadAll(io.LimitReader(r.Body, int64(maxPacketSize)+1))
	if err != nil {
		http.Error(w, "failed to read body", http.StatusBadRequest)
		return
	}
	if len(innerPacket) == 0 {
		http.Error(w, "empty packet", http.StatusBadRequest)
		return
	}
	if len(innerPacket) > maxPacketSize {
		http.Error(w, "packet too large", http.StatusBadRequest)
		return
	}
	n := len(innerPacket)

	// Extract the counter from the inner packet header (bytes [16:24], big-endian uint64).
	// The NHP server echoes this counter in its ACK/COK response, so we use it
	// to match the response back to this HTTP request.
	if n < 24 {
		http.Error(w, "inner packet too short", http.StatusBadRequest)
		return
	}
	innerCounter := binary.BigEndian.Uint64(innerPacket[16:24])

	// Extract real client address before picking an instance so sticky
	// sessions can hash on it.
	realAddr, err := realClientAddr(r)
	if err != nil {
		log.Error("[Relay] %v", err)

View on GitHub (pinned to 6e04ca5ff0)