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
- Check the relay is not coalescing multiple datagrams into one forward
- Ensure the inner packet is a standard NHP packet within the max UDP payload size
- Update relay/server to matching versions if the max packet size changed
- 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
- Keep relay forwarding one datagram per forward
- Enforce the max packet size at the relay edge
- Keep relay and server versions aligned
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
- relay source address
- relay: privateKeyBase64 must be set in config
- relay: no upstream configured; add at least one [[Servers]]…
- relay: server # missing publicKeyBase64
- relay: server # (fingerprint ) has no [[Servers.Instances]]
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 onView on GitHub (pinned to 6e04ca5ff0)