slackhq/nebula · warning
ErrAlreadySeen
ErrAlreadySeen
Error message
already seen
What it means
ErrAlreadySeen indicates a packet failed the replay window check: its message counter was already processed by this connection, so decryption is refused to prevent replay attacks. Declared in handshake_manager.go alongside the hostmap errors, it is returned by ConnectionState Decrypt/VerifyRelay when the replay filter rejects the counter.
Source
Thrown at handshake_manager.go:415
// Add any calculated remotes, and trigger early handshake if one found
doTrigger = hm.lightHouse.addCalculatedRemotes(vpnAddr)
}
if doTrigger {
select {
case hm.trigger <- vpnAddr:
default:
}
}
hm.Unlock()
hm.lightHouse.QueryServer(vpnAddr)
return hostinfo
}
var (
ErrExistingHostInfo = errors.New("existing hostinfo")
ErrAlreadySeen = errors.New("already seen")
ErrLocalIndexCollision = errors.New("local index collision")
)
// CheckAndComplete checks for any conflicts in the main and pending hostmap
// before adding hostinfo to main. If err is nil, it was added. Otherwise err will be:
//
// ErrAlreadySeen if we already have an entry in the hostmap that has seen the
// exact same handshake packet
//
// ErrExistingHostInfo if we already have an entry in the hostmap for this
// VpnIp and the new handshake was older than the one we currently have
//
// ErrLocalIndexCollision if we already have an entry in the main or pending
// hostmap for the hostinfo.localIndexId.
func (hm *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket uint8, f *Interface) (*HostInfo, error) {
hm.mainHostMap.Lock()
defer hm.mainHostMap.Unlock()
hm.Lock()View on GitHub (pinned to dd8f660c0a)
Solutions
- Treat isolated occurrences as benign network duplication and drop the packet
- If frequent, investigate path duplication (bonded links, redundant routing, virtual NICs) delivering every packet twice
- Ensure counters are not reset out-of-band (e.g. reloading an old hostinfo snapshot) which would make new traffic look replayed
Defensive patterns
Strategy: try-catch
Try / catch
out, err := cs.Decrypt(b, out)
if errors.Is(err, ErrAlreadySeen) {
// replayed or duplicate packet: drop silently
return
} Prevention
- Expect duplicates on redundant/lossy networks and drop them quietly
- Never reset or reload connection counters while a tunnel is live
- Alert on replay rates far above baseline (possible replay attack)
When it happens
Trigger: Calling Decrypt or VerifyRelay on connection_state.go:104/116 where the NaCl/decrypt verification reports the message counter was already seen (result == false under cs.decryptLock).
Common situations: Duplicate UDP packets delivered by the network; packet replay (possibly malicious); out-of-order retransmits at the tunnel layer; restoring old packet captures onto a live connection.
Related errors
- use of Curve25519 is not allowed in FIPS 140-only mode
- use of Curve25519 is not allowed in FIPS 140-only mode
- use of Curve25519 is not allowed in FIPS 140-only mode
- ErrUnknownNetworkType
- ErrOutOfWindow
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/38c3d3de6501c540.
Report an issue: GitHub.