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 presentView on GitHub (pinned to dd8f660c0a)
Solutions
- Remove the duplicate v2 certificate so pki.cert contains at most one v2 certificate
- If renewing, replace the old certificate entirely instead of appending
- 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 renewing certificates, replace pki.cert atomically instead of appending
- Audit config-management templates that concatenate PEM bundles
- Run nebula-cert print -path pki.cert in CI to count certificates
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- v1 certificate already found in pki.cert
- error while unmarshaling pki.cert: %w
- no networks encoded in certificate
- host certificate is a CA certificate
- error while adding CA certificate to CA trust store: %s
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/9dfb1759a4c19f2f.
Report an issue: GitHub.