{"record":{"id":"40c497a8b188ced4","repo":"slackhq/nebula","slug":"erroutofwindow","errorCode":"ErrOutOfWindow","errorMessage":"out of window packet","messagePattern":"out of window packet","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"outside.go","lineNumber":24,"sourceCode":"\t\"errors\"\n\t\"log/slog\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"golang.org/x/net/ipv6\"\n\n\t\"github.com/slackhq/nebula/firewall\"\n\t\"github.com/slackhq/nebula/header\"\n\t\"github.com/slackhq/nebula/iputil\"\n\t\"github.com/slackhq/nebula/overlay/batch\"\n\t\"golang.org/x/net/ipv4\"\n)\n\nconst (\n\tminFwPacketLen = 4\n)\n\nvar ErrOutOfWindow = errors.New(\"out of window packet\")\n\n// readOutsidePackets processes one received underlay packet.\n// Message payloads are decrypted IN PLACE, so packet must stay untouched\n// by the caller until the batcher for queue q has been flushed\nfunc (f *Interface) readOutsidePackets(via ViaSender, packet []byte, rxc *rxContext) {\n\th := rxc.h\n\terr := h.Parse(packet)\n\tif err != nil {\n\t\t// Hole punch packets are 0 or 1 byte big, so lets ignore printing those errors\n\t\t// TODO: record metrics for rx holepunch/punchy packets?\n\t\tif len(packet) > 1 {\n\t\t\tf.messageMetrics.RxInvalid(1)\n\t\t\tif f.l.Enabled(context.Background(), slog.LevelDebug) {\n\t\t\t\tf.l.Debug(\"Error while parsing inbound packet\",\n\t\t\t\t\t\"from\", via,\n\t\t\t\t\t\"error\", err,\n\t\t\t\t\t\"packet\", packet,\n\t\t\t\t)","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/outside.go#L6-L42","documentation":"ErrOutOfWindow is declared in outside.go's underlay packet-processing path. Received handshake/data packets carry a message counter; packets whose counter falls outside the replay window (already seen or too old) are rejected with this error to prevent replay attacks.","triggerScenarios":"readOutsidePackets receives a packet whose counter is outside the sliding replay window for the session, or a too-short packet (< minFwPacketLen = 4 bytes) fails initial validation.","commonSituations":"Heavy packet reordering or duplication on lossy underlay networks, packets arriving after a rekey invalidated the old window, MTU/proxy mangling truncating packets below 4 bytes.","solutions":["Verify both peers share the same session key epoch; force a re-handshake if a rekey just occurred.","Check the underlay network for excessive reordering/duplication (NATs, load-balanced anycast).","Capture the offending packet and confirm its length is >= 4 bytes and counters are monotonic."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if len(packet) < minFwPacketLen {\n    return fmt.Errorf(\"underlay packet too short: %d\", len(packet))\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, outside.ErrOutOfWindow) {\n    // drop packet; if rate is high, re-handshake or investigate underlay\n}","preventionTips":["Monitor out-of-window drop rates as an underlay health signal.","Avoid prolonged packet reordering (multi-path/anycast underlays).","Re-handshake promptly after key rotation."],"tags":["replay-window","packet-processing","network"],"backgroundTag":"replay-window-violation","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}