slackhq/nebula · error
ErrMachineFailed
ErrMachineFailed
Error message
handshake machine has failed
What it means
ErrMachineFailed is returned by Initiate and ProcessPacket when the handshake Machine has already entered a failed state from a previous error (every failure path sets m.failed = true). Once failed, the machine is permanently unusable by design; the caller must construct a new Machine. This guards against using a machine with corrupted or inconsistent handshake state.
Source
Thrown at handshake/errors.go:12
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
- Check m.Failed() before reuse and construct a new Machine via NewMachine when true
- Handle the original error that failed the machine (fix keys/certs/network) before retrying
- Never share one Machine across goroutines or handshake attempts; one machine per handshake
Example fix
// before
res, err := m.ProcessPacket(out, pkt)
if err != nil {
res, err = m.ProcessPacket(out, pkt) // ErrMachineFailed
}
// after
res, err := m.ProcessPacket(out, pkt)
if err != nil {
m, err = handshake.NewMachine(cs, version, getCred) // fresh machine
res, err = m.ProcessPacket(out, pkt)
} Defensive patterns
Strategy: type-guard
Validate before calling
if m.Failed() {
return errors.New("handshake machine failed; create a new one")
} Type guard
func machineUsable(m *handshake.Machine) bool {
return m != nil && !m.Failed()
} Try / catch
res, err := m.ProcessPacket(out, pkt)
if errors.Is(err, handshake.ErrMachineFailed) {
// machine is dead by design: never retry on it, recreate
m = newHandshakeMachine()
} Prevention
- Check Failed() before every reuse of a Machine
- One Machine per handshake attempt; discard on first error
- Log the first error that failed the machine — ErrMachineFailed masks it
When it happens
Trigger: Calling m.Initiate(out) or m.ProcessPacket(out, packet) after any earlier call on the same Machine returned an error that set m.failed (e.g. ErrPublicKeyMismatch, ErrMissingContent, ErrSubtypeMismatch).
Common situations: Reusing a Machine object across retry loops after a failed handshake; a caller ignoring the first error and continuing to feed packets into the dead machine.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- ErrInitiateOnResponder
- ErrInitiateAlreadyCalled
- ErrInitiateNotCalled
- ErrIncompleteHandshake
- ErrMissingContent
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/f1f00d5f4cc65d70.
Report an issue: GitHub.