slackhq/nebula · critical

ErrNoCredential

ErrNoCredential

Error message

%w: %v

What it means

ErrNoCredential is returned during outgoing handshake marshaling when the node is asked to include its certificate (flags.expectsCert) but no certificate credential is available for the local certificate version m.myVersion. getCred(myVersion) returned nil, meaning the local cert store has no usable certificate for that version.

Source

Thrown at handshake/machine.go:409

			if err != nil {
				return nil, fmt.Errorf("%w: %w", ErrIndexAllocation, err)
			}
			m.result.LocalIndex = index
			m.indexAllocated = true
		}

		if m.result.Initiator {
			p.InitiatorIndex = m.result.LocalIndex
		} else {
			p.ResponderIndex = m.result.LocalIndex
			p.InitiatorIndex = m.result.RemoteIndex
		}
		p.Time = uint64(time.Now().UnixNano())
	}
	if flags.expectsCert {
		cred := m.getCred(m.myVersion)
		if cred == nil {
			return nil, fmt.Errorf("%w: %v", ErrNoCredential, m.myVersion)
		}
		p.Cert = cred.Bytes
		p.CertVersion = uint32(cred.Cert.Version())
		m.result.MyCert = cred.Cert
	}

	return MarshalPayload(nil, p), nil
}

func (m *Machine) buildResponse(out []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
	flags := m.myMsgFlags()
	hsBytes, err := m.marshalOutgoing(flags)
	if err != nil {
		return nil, nil, nil, err
	}

	// Extend out by header.Len to make room for the header. slices.Grow is a
	// no-op when the cap is already sufficient (the zero-copy case where the

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Load a certificate matching the machine's myVersion before initiating handshakes (check cert build/version)
  2. Re-issue or convert the host certificate to the expected version format
  3. Verify config 'pki' paths point to a valid cert/key pair and that startup loading succeeded
  4. Upgrade/downgrade the nebula binary so myVersion matches the certificate version

Example fix

// before: machine built with myVersion = cert.Version2 but only a v1 cert loaded
// after: ensure the loaded credential version matches
cred := m.getCred(m.myVersion)
if cred == nil {
    // re-load or re-sign the host cert for the required version
    return nil, fmt.Errorf("no %v credential loaded; update pki cert", m.myVersion)
}
Defensive patterns

Strategy: validation

Validate before calling

cred := m.getCred(m.myVersion)
if cred == nil {
    return errors.New("no local certificate loaded for handshake version; fix pki config before initiating")
}

Type guard

func hasCredential(m *Machine) bool {
    return m.getCred(m.myVersion) != nil
}

Prevention

When it happens

Trigger: Calling handshake Initiate/buildResponse when expectsCert is set but the local host has no certificate loaded for the current myVersion (e.g. cert v1 vs v2 mismatch between loaded credentials and machine version).

Common situations: Starting nebula with a v2 certificate while the handshake machine is pinned to v1 (or vice versa); cert failed to load/parse at startup; cert was removed by a reload; mixing node versions in a rolling upgrade.

Related errors


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