slackhq/nebula · error

v2 certificate already found in pki.cert

Error message

v2 certificate already found in pki.cert

What it means

newCertStateFromConfig parses the pki.cert file/PEM which may contain multiple certificates (a v1 and a v2 certificate). It keeps one slot per version; if it encounters a second certificate of the same version it aborts, because nebula requires exactly zero or one certificate per version in pki.cert.

Source

Thrown at pki.go:352

		// Load the certificate
		crt, rawCert, err = loadCertificate(rawCert)
		if err != nil {
			return nil, err
		}

		if fips140.Enforced() && crt.Curve() != cert.Curve_P256 {
			return nil, fmt.Errorf("pki: use of %s is not allowed in FIPS 140-only mode", crt.Curve())
		}

		switch crt.Version() {
		case cert.Version1:
			if v1 != nil {
				return nil, fmt.Errorf("v1 certificate already found in pki.cert")
			}
			v1 = crt
		case cert.Version2:
			if v2 != nil {
				return nil, fmt.Errorf("v2 certificate already found in pki.cert")
			}
			v2 = crt
		default:
			return nil, fmt.Errorf("unknown certificate version %v", crt.Version())
		}

		if len(rawCert) == 0 || strings.TrimSpace(string(rawCert)) == "" {
			break
		}
	}

	if v1 == nil && v2 == nil {
		return nil, errors.New("no certificates found in pki.cert")
	}

	useInitiatingVersion := uint32(1)
	if v1 == nil {
		// The only condition that requires v2 as the default is if only a v2 certificate is present

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Remove the duplicate v2 certificate so pki.cert contains at most one v2 certificate
  2. If renewing, replace the old certificate entirely instead of appending
  3. Verify with: openssl crl2pkcs7 -nocrl -certfile pki.cert | openssl pkcs7 -print_certs -noout

Example fix

// before (pki.cert: old v2 cert + new v2 cert concatenated)
-----BEGIN NEBULA CERTIFICATE-----
(old v2)
-----END NEBULA CERTIFICATE-----
-----BEGIN NEBULA CERTIFICATE-----
(new v2)
-----END NEBULA CERTIFICATE-----
// after (only the new v2 cert)
-----BEGIN NEBULA CERTIFICATE-----
(new v2)
-----END NEBULA CERTIFICATE-----
Defensive patterns

Strategy: validation

Validate before calling

// before reload: ensure at most one cert per version in pki.cert
import "github.com/slushie/..." // nebula cert pkg
func validateSingleCertsPerVersion(pkiCertPEM []byte) error {
    seen := map[string]bool{}
    rest := pkiCertPEM
    for {
        crt, r, err := cert.UnmarshalCertificate(rest)
        if err != nil { break }
        rest = r
        v := crt.Version().String()
        if seen[v] { return fmt.Errorf("duplicate %s certificate in pki.cert", v) }
        seen[v] = true
        if len(rest) == 0 { break }
    }
    return nil
}

Type guard

func hasDupVersion(crts []cert.Certificate) bool {
    seen := map[cert.Version]bool{}
    for _, c := range crts {
        v := c.Version()
        if seen[v] { return true }
        seen[v] = true
    }
    return false
}

Prevention

When it happens

Trigger: newCertStateFromConfig (via reloadCerts) reads pki.cert and finds two cert.Version2 certificates concatenated in the PEM bundle.

Common situations: Appending a renewed v2 certificate to the existing pki.cert instead of replacing it; concatenating multiple hosts' certs; copying the same file twice during automation.

Understand the failure class

Related errors


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