slackhq/nebula · error
ErrNotCA
ErrNotCA
Error message
certificate is not a CA
What it means
Sentinel error ErrNotCA returned by CAPool.AddCA when a certificate is added to the CA pool but its IsCA() flag is false. It fires because only CA certificates may anchor trust in the pool; the offending input is the certificate named in the wrapping fmt.Errorf (its Name()).
Source
Thrown at cert/errors.go:12
package cert
import (
"errors"
"fmt"
)
var (
ErrBadFormat = errors.New("bad wire format")
ErrRootExpired = errors.New("root certificate is expired")
ErrExpired = errors.New("certificate is expired")
ErrNotCA = errors.New("certificate is not a CA")
ErrNotSelfSigned = errors.New("certificate is not self-signed")
ErrBlockListed = errors.New("certificate is in the block list")
ErrFingerprintMismatch = errors.New("certificate fingerprint did not match")
ErrSignatureMismatch = errors.New("certificate signature did not match")
ErrInvalidPublicKey = errors.New("invalid public key")
ErrInvalidPrivateKey = errors.New("invalid private key")
ErrPublicPrivateCurveMismatch = errors.New("public key does not match private key curve")
ErrPublicPrivateKeyMismatch = errors.New("public key and private key are not a pair")
ErrPrivateKeyEncrypted = errors.New("private key must be decrypted")
ErrCaNotFound = errors.New("could not find ca for the certificate")
ErrUnknownVersion = errors.New("certificate version unrecognized")
ErrCertPubkeyPresent = errors.New("certificate has unexpected pubkey present")
ErrCurveMismatch = errors.New("certificate curve does not match CA")
ErrInvalidPEMBlock = errors.New("input did not contain a valid PEM encoded block")
ErrInvalidPEMCertificateBanner = errors.New("bytes did not contain a proper certificate banner")
ErrInvalidPEMX25519PublicKeyBanner = errors.New("bytes did not contain a proper X25519 public key banner")
ErrInvalidPEMX25519PrivateKeyBanner = errors.New("bytes did not contain a proper X25519 private key banner")View on GitHub (pinned to dd8f660c0a)
Solutions
- Ensure the file passed to the pool contains CA certificates (signed with nebula-cert ca / ca:true), not node certificates.
- Regenerate the CA with nebula-cert ca so the CA flag and constraints are set.
- Match the wrapped error with errors.Is(err, cert.ErrNotCA) — the message includes the cert name prefix.
Example fix
// before
leaf, _ := cert.UnmarshalCertificateV2(hostCertBytes)
pool.AddCA(leaf) // error: <name>: certificate is not a CA
// after
ca, _ := cert.UnmarshalCertificateV2(caCertBytes)
err := pool.AddCA(ca)
if err != nil && !errors.Is(err, cert.ErrNotCA) { return err } Defensive patterns
Strategy: validation
Validate before calling
for _, ca := range candidateCAs {
if !ca.IsCA() {
return fmt.Errorf("%s lacks CA flag; use the root CA file", ca.Name())
}
} Type guard
func isCA(c cert.Certificate) bool {
return c.IsCA()
} Try / catch
err := pool.AddCA(c)
if errors.Is(err, cert.ErrNotCA) {
return fmt.Errorf("%s is a leaf cert, not a CA: %v", c.Name(), err)
} Prevention
- Keep ca.crt (CA certs) and host.crt (leaf certs) in separate files/paths.
- Match with errors.Is — AddCA wraps the message with the cert name.
- Generate CAs only via nebula-cert ca so IsCA is set.
When it happens
Trigger: Calling pool.AddCA(c) — directly or via NewCAPoolFromBytes/NewCAPoolFromPEMReader — with a certificate whose details.IsCA is false. Note the error is wrapped: fmt.Errorf("%s: %w", c.Name(), ErrNotCA), so match with errors.Is.
Common situations: Pointing the ca-file config at a leaf/host certificate instead of the CA; pem files built by concatenating agent certs with CA certs; regenerated certs that lost the CA flag because the signing tool omitted -subca or is-ca flags.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- ErrNotSelfSigned
- ErrInvalidPublicKey
- %s: %w
- could not calculate fingerprint for provided CA; error: %w;
- no certificate
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/b66ad1c0d8fc730e.
Report an issue: GitHub.