slackhq/nebula · warning

ErrSubtypeMismatch

ErrSubtypeMismatch

Error message

packet subtype does not match handshake machine subtype

What it means

ErrSubtypeMismatch is returned by ProcessPacket when the packet's MessageSubType byte does not match the subtype the handshake Machine was constructed for. The machine drops the packet without failing, so a legitimate retransmit can still complete later.

Source

Thrown at handshake/errors.go:21

import "errors"

var (
	ErrInitiateOnResponder     = errors.New("initiate called on responder")
	ErrInitiateAlreadyCalled   = errors.New("initiate already called")
	ErrInitiateNotCalled       = errors.New("initiate must be called before ProcessPacket for initiators")
	ErrPacketTooShort          = errors.New("packet too short")
	ErrPublicKeyMismatch       = errors.New("public key mismatch between certificate and handshake")
	ErrIncompleteHandshake     = errors.New("handshake completed without receiving required content")
	ErrMachineFailed           = errors.New("handshake machine has failed")
	ErrUnknownSubtype          = errors.New("unknown handshake subtype")
	ErrMissingContent          = errors.New("expected handshake content but message was empty")
	ErrUnexpectedContent       = errors.New("received unexpected handshake content")
	ErrInvalidRemoteIndex      = errors.New("peer sent an invalid index in handshake payload")
	ErrIndexAllocation         = errors.New("failed to allocate local index")
	ErrNoCredential            = errors.New("no handshake credential available for cert version")
	ErrAsymmetricCipherKeys    = errors.New("noise produced only one cipher key")
	ErrMultiMessageUnsupported = errors.New("multi-message handshake patterns are not yet supported by the manager")
	ErrSubtypeMismatch         = errors.New("packet subtype does not match handshake machine subtype")
)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Verify both peers configure the same handshake message subtype (e.g. HandshakeIXPSK0 vs HandshakeXXPSK0)
  2. Check that the UDP listener isn't receiving handshake packets from other tunnels or hosts (stray traffic); safe to ignore
  3. Inspect packet[1] in the offending packet to confirm the subtype being sent

Example fix

// before
machine := NewMachine(cs, version, initiator, HandshakeXXPSK0)
// after (match the peer)
machine := NewMachine(cs, version, initiator, HandshakeIXPSK0)
Defensive patterns

Strategy: validation

Validate before calling

if header.MessageSubType(packet[1]) != expectedSubtype {
    // drop packet; would cause handshake.ErrSubtypeMismatch
    return
}

Try / catch

_, _, err := m.ProcessPacket(nil, packet)
if errors.Is(err, handshake.ErrSubtypeMismatch) {
    // safe to ignore: machine is not killed, legit retransmits still work
    return
}

Prevention

When it happens

Trigger: Feeding ProcessPacket (handshake/machine.go:216) a handshake packet whose header subtype differs from m.subtype — e.g. an IX PSK0 packet delivered to a machine expecting XX PSK0, or cross-wired UDP ports delivering foreign handshake packets.

Common situations: Two nodes configured with different handshake subtypes trying to connect; stray handshake traffic from another tunnel/overlay landing on the same UDP port; misconfigured firewall/port-forward routing handshake packets to the wrong host.

Understand the failure class

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/1e3f661dca1ecee6. Report an issue: GitHub.