{"record":{"id":"b66ad1c0d8fc730e","repo":"slackhq/nebula","slug":"errnotca","errorCode":"ErrNotCA","errorMessage":"certificate is not a CA","messagePattern":"certificate is not a CA","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/errors.go","lineNumber":12,"sourceCode":"package cert\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\tErrBadFormat                  = errors.New(\"bad wire format\")\n\tErrRootExpired                = errors.New(\"root certificate is expired\")\n\tErrExpired                    = errors.New(\"certificate is expired\")\n\tErrNotCA                      = errors.New(\"certificate is not a CA\")\n\tErrNotSelfSigned              = errors.New(\"certificate is not self-signed\")\n\tErrBlockListed                = errors.New(\"certificate is in the block list\")\n\tErrFingerprintMismatch        = errors.New(\"certificate fingerprint did not match\")\n\tErrSignatureMismatch          = errors.New(\"certificate signature did not match\")\n\tErrInvalidPublicKey           = errors.New(\"invalid public key\")\n\tErrInvalidPrivateKey          = errors.New(\"invalid private key\")\n\tErrPublicPrivateCurveMismatch = errors.New(\"public key does not match private key curve\")\n\tErrPublicPrivateKeyMismatch   = errors.New(\"public key and private key are not a pair\")\n\tErrPrivateKeyEncrypted        = errors.New(\"private key must be decrypted\")\n\tErrCaNotFound                 = errors.New(\"could not find ca for the certificate\")\n\tErrUnknownVersion             = errors.New(\"certificate version unrecognized\")\n\tErrCertPubkeyPresent          = errors.New(\"certificate has unexpected pubkey present\")\n\tErrCurveMismatch              = errors.New(\"certificate curve does not match CA\")\n\n\tErrInvalidPEMBlock                   = errors.New(\"input did not contain a valid PEM encoded block\")\n\tErrInvalidPEMCertificateBanner       = errors.New(\"bytes did not contain a proper certificate banner\")\n\tErrInvalidPEMX25519PublicKeyBanner   = errors.New(\"bytes did not contain a proper X25519 public key banner\")\n\tErrInvalidPEMX25519PrivateKeyBanner  = errors.New(\"bytes did not contain a proper X25519 private key banner\")","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/errors.go#L1-L30","documentation":"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()).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nleaf, _ := cert.UnmarshalCertificateV2(hostCertBytes)\npool.AddCA(leaf) // error: <name>: certificate is not a CA\n\n// after\nca, _ := cert.UnmarshalCertificateV2(caCertBytes)\nerr := pool.AddCA(ca)\nif err != nil && !errors.Is(err, cert.ErrNotCA) { return err }","handlingStrategy":"validation","validationCode":"for _, ca := range candidateCAs {\n    if !ca.IsCA() {\n        return fmt.Errorf(\"%s lacks CA flag; use the root CA file\", ca.Name())\n    }\n}","typeGuard":"func isCA(c cert.Certificate) bool {\n    return c.IsCA()\n}","tryCatchPattern":"err := pool.AddCA(c)\nif errors.Is(err, cert.ErrNotCA) {\n    return fmt.Errorf(\"%s is a leaf cert, not a CA: %v\", c.Name(), err)\n}","preventionTips":["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."],"tags":["certificate","ca-pool","validation"],"backgroundTag":"certificate-not-a-ca","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}