slackhq/nebula · error

ErrUnexpectedContent

ErrUnexpectedContent

Error message

received unexpected handshake content

What it means

ErrUnexpectedContent is returned by processPayload when a handshake message contains payload data (or certificate data) but the pattern flags say this message should not carry it, or vice versa. It enforces that each message's content matches the expected pattern; the machine is marked failed. The check exists at handshake/machine.go:304 for payloads and :310 for certificates.

Source

Thrown at handshake/errors.go:15

package handshake

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. Align both peers on the same handshake pattern so content placement matches
  2. Remove or add payload/cert attachment in the peer's message construction to match the pattern
  3. Upgrade/downgrade the peer library to a version with matching message layout

Example fix

// before: cert attached to message 1 where pattern expects it in message 2
msg1 := append(m.hs.WriteMessage(), cert...)

// after
msg1 := m.hs.WriteMessage()
msg2 := handshake.AppendCert(m.hs.WriteMessage(), cert)
Defensive patterns

Strategy: validation

Validate before calling

if flags.ExpectsPayload == hasPayload(msg) && flags.ExpectsCert == hasCert(msg) {
    // message layout matches pattern; safe to process
}

Type guard

func contentMatchesPattern(msg []byte, flags handshake.MsgFlags) bool {
    return handshake.HasPayload(msg) == flags.ExpectsPayload &&
        handshake.HasCert(msg) == flags.ExpectsCert
}

Try / catch

res, err := m.ProcessPacket(out, pkt)
if errors.Is(err, handshake.ErrUnexpectedContent) {
    log.Printf("peer %s violates handshake message layout", conn.RemoteAddr())
    conn.Close() // protocol violation, not retryable
    return
}

Prevention

When it happens

Trigger: hasPayloadData != flags.expectsPayload (machine.go:304) or hasCertData != flags.expectsCert (machine.go:310) while processing a decrypted handshake message.

Common situations: Peer library version sends cert in a different message position; hand-rolled or test peer emits extra data; mixing handshake patterns between peers of different configurations.

Understand the failure class

Related errors


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