slackhq/nebula · error

ErrNotSelfSigned

ErrNotSelfSigned

Error message

certificate is not self-signed

What it means

ErrNotSelfSigned is returned by CAPool.AddCA when the candidate CA certificate's signature cannot be verified with its own public key (CheckSignature(c.PublicKey()) fails). A trust anchor must be self-signed.

Source

Thrown at cert/errors.go:13

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")
	ErrInvalidPEMEd25519PublicKeyBanner  = errors.New("bytes did not contain a proper Ed25519 public key banner")

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Add the root self-signed CA certificate to the pool, not an intermediate or leaf.
  2. Re-verify the certificate file integrity (checksums, clean re-download).
  3. If using intermediates, chain them properly and add only the self-signed root to CAPool.
  4. Handle the wrapped format with errors.Is(err, cert.ErrNotSelfSigned) since AddCA wraps it with the cert name.

Example fix

// before
pool.AddCA(intermediateCert) // not self-signed

// after
pool.AddCA(rootCACert) // self-signed trust anchor
Defensive patterns

Strategy: validation

Validate before calling

if !c.CheckSignature(c.PublicKey()) {
    return fmt.Errorf("%s is not self-signed; add the root CA instead", c.Name())
}

Type guard

func isSelfSigned(c cert.Certificate) bool {
    return c.CheckSignature(c.PublicKey())
}

Try / catch

err := pool.AddCA(c)
if errors.Is(err, cert.ErrNotSelfSigned) {
    return fmt.Errorf("%s is signed by another CA; load the self-signed root", c.Name())
}

Prevention

When it happens

Trigger: pool.AddCA(c) is called and c.CheckSignature(c.PublicKey()) returns false — i.e., the cert was signed by another key rather than its own, or the signature bytes/cipher are corrupt.

Common situations: Adding an intermediate or leaf certificate (signed by the root) directly into the pool instead of the self-signed root; corrupted cert bytes; certs hand-mangled during distribution.

Understand the failure class

Related errors


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