slackhq/nebula · error

ErrNoCredential

ErrNoCredential

Error message

no handshake credential available for cert version

What it means

ErrNoCredential is returned by NewMachine, validateCert, and marshalOutgoing when getCred(version) finds no handshake credential registered for the required certificate version. The node cannot sign or validate certificates for that version without the matching credential. It is wrapped with the requested version number for diagnostics.

Source

Thrown at handshake/errors.go:18

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. Register/load a credential for the required cert version before starting handshakes (verify getCred returns non-nil)
  2. Check the credentials directory/key files are present and readable in the deployment
  3. Align cert versions between peers, or add support for the peer's version
  4. Gate handshake serving behind credential-load completion to avoid startup races

Example fix

// before
m, err := handshake.NewMachine(cs, 2, getCred) // getCcred(nil) for v2

// after
if getCred(2) == nil {
    return fmt.Errorf("credentials for cert version 2 not loaded")
}
m, err := handshake.NewMachine(cs, 2, getCred)
Defensive patterns

Strategy: validation

Validate before calling

if getCred(certVersion) == nil {
    return fmt.Errorf("no handshake credential loaded for cert version %d", certVersion)
}

Type guard

func credentialsReady(versions ...int) bool {
    for _, v := range versions {
        if getCred(v) == nil {
            return false
        }
    }
    return true
}

Try / catch

m, err := handshake.NewMachine(cs, version, getCred)
if errors.Is(err, handshake.ErrNoCredential) {
    log.Printf("credential for version %v missing; refusing handshake", version)
    return
}

Prevention

When it happens

Trigger: NewMachine (machine.go:91) builds a machine for a version whose credential lookup returns nil; validateCert (machine.go:346) hits the same during a handshake when m.myVersion has no registered credential.

Common situations: Credential store not yet loaded at handshake time (startup race); peer requests a newer certificate version than this node has keys for; credentials directory misconfigured or empty after redeploy; version bump without distributing new keys.

Understand the failure class

Related errors


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