slackhq/nebula · error
ErrInitiateNotCalled
ErrInitiateNotCalled
Error message
initiate must be called before ProcessPacket for initiators
What it means
ErrInitiateNotCalled is returned by Machine.ProcessPacket when the machine is an initiator but its handshake state is still at message index 0, meaning Initiate() was never called. An initiator must send the first handshake message before it can process any packet.
Source
Thrown at handshake/errors.go:8
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
- Call m.Initiate(payload) first and send the returned packet before processing any incoming packets.
- Reorder startup logic so Initiate is guaranteed to run before the read loop calls ProcessPacket.
- Verify the machine was constructed with the intended initiator flag.
Example fix
// before packet := make([]byte, 100) msg, _, err := m.ProcessPacket(nil, packet) // initiate never called // after initPacket, err := m.Initiate(nil) conn.Write(initPacket) msg, _, err := m.ProcessPacket(nil, packet)
Defensive patterns
Strategy: try-catch
Validate before calling
if m.result.Initiator && !initiated {
return errors.New("call Initiate before ProcessPacket")
} Type guard
func readyToProcess(m *handshake.Machine) bool {
r := m.Result()
return !m.Failed() && (!r.Initiator || initiatedFlag)
} Try / catch
msg, packet, err := m.ProcessPacket(h, buf)
if errors.Is(err, handshake.ErrInitiateNotCalled) {
// must initiate first: build and send init packet before processing
} Prevention
- Always run Initiate and send its packet before starting the read loop
- Sequence startup: initiate → write → then process incoming packets
- Initialize machines and handshakes in one place to enforce ordering
- Add tests that exercise the full initiator flow before processing
When it happens
Trigger: Calling ProcessPacket on an initiator Machine before ever calling Initiate, as in handshake/machine.go:220 (m.result.Initiator && m.hs.MessageIndex() == 0).
Common situations: Event-driven code that starts reading from the socket before sending the initiation message; wiring where incoming packets reach the machine before Initiate is invoked; tests feeding a packet to a fresh initiator.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/281db234a4003aa3.
Report an issue: GitHub.