slackhq/nebula · error

v1 certificate already found in pki.cert

Error message

v1 certificate already found in pki.cert

What it means

pki.cert may contain a chain of certificates, but at most one v1 certificate and one v2 certificate are allowed. If a second cert.Version1 certificate is encountered during parsing, this error is returned to reject the malformed file.

Source

Thrown at pki.go:347

		}
	}

	var crt, v1, v2 cert.Certificate
	for {
		// 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")

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Edit pki.cert to keep exactly one v1 certificate (plus at most one v2) and remove the duplicate.
  2. Regenerate pki.cert cleanly from the single intended certificate file.
  3. Fix any `cat old.cert >> pki.cert` rotation scripts to use atomic replace instead of append.
  4. Verify afterwards with openssl/nebula-cert tooling that the file parses as a single chain.

Example fix

# before (rotating)
cat new.cert >> /etc/nebula/pki.cert
# after (rotating)
install -m 0644 new.cert /etc/nebula/pki.cert
Defensive patterns

Strategy: validation

Validate before calling

// Before reload: count v1/v2 PEM blocks in pki.cert
func checkSingleCerts(raw []byte) error {
  rest := raw; v1, v2 := 0, 0
  for len(rest) > 0 {
    var crt *x509.Certificate
    crt, rest, _ = parseOne(rest)
    switch crt.Version {
    case 1: v1++
    case 2: v2++
    }
    if v1 > 1 { return errors.New("pki.cert contains multiple v1 certificates") }
    if v2 > 1 { return errors.New("pki.cert contains multiple v2 certificates") }
  }
  return nil
}

Try / catch

cs, err := newCertStateFromConfig(...)
if err != nil {
  if strings.Contains(err.Error(), "already found in pki.cert") {
    return fmt.Errorf("pki.cert has duplicate certs; rebuild it as a single chain: %w", err)
  }
  return err
}

Prevention

When it happens

Trigger: reloadCerts -> newCertStateFromConfig when pki.cert contains two or more v1-format certificates, typically from concatenating two complete cert files or appending a renewed cert of the same version instead of replacing it.

Common situations: Operators concatenating old and new certs during rotation; shell redirection with `>>` instead of `>` overwriting pki.cert; packaging scripts bundling multiple intermediates of the same version; copy-paste mishaps joining two PEM blobs.

Understand the failure class

Related errors


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