slackhq/nebula · error

ErrInvalidRemoteIndex

ErrInvalidRemoteIndex

Error message

peer sent an invalid index in handshake payload

What it means

ErrInvalidRemoteIndex is returned by processPayload when the peer's handshake payload carries a remote index of 0, which is not a valid allocated index in this protocol. Index 0 is reserved/invalid, so receiving it indicates a malformed payload from the peer; the machine is marked failed and the result's RemoteIndex stays zero.

Source

Thrown at handshake/errors.go:16

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. Fix the peer so it allocates a nonzero local index before marshaling its payload
  2. Ensure the peer's index allocator is initialized and healthy (check its logs for allocation errors)
  3. Retry the handshake; if repeated, drop connections from that peer as potentially hostile

Example fix

// before
p := handshake.Payload{Time: now} // InitiatorIndex defaults to 0

// after
idx, err := indexMgr.Alloc()
if err != nil { return err }
p := handshake.Payload{InitiatorIndex: idx, Time: now}
Defensive patterns

Strategy: validation

Validate before calling

p := handshake.Payload{InitiatorIndex: myIndex, Time: now}
if p.InitiatorIndex == 0 {
    return errors.New("refusing to send payload with zero index")
}

Type guard

func validRemoteIndex(p handshake.Payload) bool {
    return p.InitiatorIndex != 0
}

Try / catch

res, err := m.ProcessPacket(out, pkt)
if errors.Is(err, handshake.ErrInvalidRemoteIndex) {
    // peer's allocator is broken or packet is hostile
    conn.Close()
    metrics.Inc("handshake_invalid_index")
    return
}

Prevention

When it happens

Trigger: processPayload parses the Payload and remoteIndex == 0 at handshake/machine.go:325; reproduced in machine_test.go:237 with Payload{InitiatorIndex: 0, Time: 1}.

Common situations: Peer failed to allocate an index before sending (its own allocator errored); uninitialized Payload struct marshaled without setting the index field; crafted/malformed packets from a non-peer host.

Understand the failure class

Related errors


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