OpenNHP/opennhp · error

inner packet too large

Error message

inner packet too large

What it means

The server allocates a pooled packet buffer for the relayed inner packet and rejects payloads larger than the fixed buffer size. This guards against oversized packets exhausting memory or breaking RecvPrecheck assumptions.

Solutions

  1. Check the relay is not coalescing multiple datagrams into one forward
  2. Ensure the inner packet is a standard NHP packet within the max UDP payload size
  3. Update relay/server to matching versions if the max packet size changed
  4. Drop or truncate the oversized payload at the relay before forwarding

Example fix

// before: relay forwards whole datagram
// after: guard at relay
if len(inner) > maxPacketSize { log.Warning("dropping oversized inner packet"); return }
Defensive patterns

Strategy: validation

Validate before calling

if len(innerBytes) > maxPacketSize {
    return fmt.Errorf("inner packet %d exceeds limit %d", len(innerBytes), maxPacketSize)
}

Prevention

When it happens

Trigger: A relay forwards innerBytes whose length exceeds len(innerPkt.Buf), i.e. larger than the device pool packet buffer capacity (typically max NHP UDP packet size).

Common situations: Misbehaving or buggy relay forwarding fragments/concatenated datagrams; malicious client tunnelling oversized payloads through a relay; UDP payload size changes after a protocol update.

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/bd7872b6ff4d35fa. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/server/msghandler.go:818

	realIP := net.ParseIP(rlyMsg.SourceAddr.Ip)
	if reason := validateRelaySourceAddr(realIP, rlyMsg.SourceAddr.Port, s.allowPrivateRelaySource.Load()); reason != "" {
		log.Warning("server-relay[HandleRelayForward] rejecting %s from relay %s: %s:%d",
			reason, ppd.ConnData.RemoteAddr.String(), rlyMsg.SourceAddr.Ip, rlyMsg.SourceAddr.Port)
		return fmt.Errorf("%s relay source address", reason)
	}
	realAddr := &net.UDPAddr{IP: realIP, Port: rlyMsg.SourceAddr.Port}

	relayAddrStr := ppd.ConnData.RemoteAddr.String()
	log.Info("server-relay[HandleRelayForward] from relay %s, real client %s, inner %d bytes",
		relayAddrStr, realAddr, len(innerBytes))

	// Allocate a pool packet for the inner bytes.
	innerPkt := s.device.AllocatePoolPacket()
	if len(innerBytes) > len(innerPkt.Buf) {
		s.device.ReleasePoolPacket(innerPkt)
		log.Warning("server-relay[HandleRelayForward] inner packet too large (%d bytes)", len(innerBytes))
		return fmt.Errorf("inner packet too large")
	}
	copy(innerPkt.Buf[:], innerBytes)
	innerPkt.Content = innerPkt.Buf[:len(innerBytes)]

	// Run standard RecvPrecheck on the inner packet.
	innerType, _, err := s.device.RecvPrecheck(innerPkt)
	if err != nil {
		s.device.ReleasePoolPacket(innerPkt)
		log.Warning("server-relay[HandleRelayForward] inner RecvPrecheck failed: %v", err)
		return err
	}
	innerPkt.HeaderType = innerType
	log.Info("server-relay[HandleRelayForward] inner [%s] from real client %s via relay %s",
		core.HeaderTypeToString(innerType), realAddr, relayAddrStr)

	// Same RKN-under-overload gate as the direct-UDP path
	// (recvPacketRoutine), but keyed on the REAL client IP rather than the
	// relay's: a relay legitimately fans out many clients, so keying on

View on GitHub (pinned to 6e04ca5ff0)