gravitational/teleport · error

chain not allowed with an empty certificate

Error message

chain not allowed with an empty certificate

What it means

In lib/subca/parsed.go, validateCertificateOverride parses the optional certificate and chain fields of a CA override. If a chain is supplied but no override certificate is set, there is no leaf/issuer anchor to attach the chain to, so the function rejects the combination with this error. The library requires the override certificate itself to be provided whenever an intermediate chain accompanies it.

Source

Thrown at lib/subca/parsed.go:268

		}
	}

	// Validate "required" fields now that we know both Certificate and PublicKey
	// are valid.
	switch {
	case co.GetDisabled() && co.GetPublicKey() == "" && co.GetCertificate() == "":
		return nil, "", errors.New("certificate or public key required")
	case co.GetDisabled():
		// OK, determined above to have either PublicKey or Certificate.
	case co.GetCertificate() == "":
		return nil, "", errors.New("certificate required")
	}

	// Chain.
	var chain []*x509.Certificate
	if len(co.GetChain()) > 0 {
		if cert == nil {
			return nil, "", errors.New("chain not allowed with an empty certificate")
		}

		// The exact number is arbitrary, the fact that a cap exists isn't.
		const maxChainLength = 10
		if len(co.GetChain()) > maxChainLength {
			return nil, "chain", fmt.Errorf(
				"certificate chain has too many entries (%d > %d)", len(co.GetChain()), maxChainLength)
		}

		chain = make([]*x509.Certificate, len(co.GetChain()))
		prev := cert
		for i, chainPEM := range co.GetChain() {
			chainCert, err := ParseCertificateOverrideCertificate(chainPEM)
			if err != nil {
				return nil, fmt.Sprintf("chain[%d]", i), err
			}
			chainSub := chainCert.Subject.String()

View on GitHub (pinned to 1283425b60)

Solutions

  1. Set the override certificate (co.Cert) to the issuing CA certificate that the chain extends.
  2. If the first certificate in your PEM is actually the override certificate, move it from 'chain' into the certificate field.
  3. If no chain is needed, remove the chain entries entirely instead of leaving them with an empty cert.

Example fix

// before
spec:
  cert: ""
  chain:
    - |
      -----BEGIN CERTIFICATE-----
      ...(intermediate)...
// after
spec:
  cert: |
    -----BEGIN CERTIFICATE-----
    ...(override CA)...
  chain:
    - |
      -----BEGIN CERTIFICATE-----
      ...(intermediate)...
Defensive patterns

Strategy: validation

Validate before calling

if len(override.Chain) > 0 && override.Cert == "" {
    return fmt.Errorf("invalid config: chain requires a certificate")
}

Prevention

When it happens

Trigger: Calling ValidateAndParseCAOverride with a CAOverride spec whose 'chain' field is non-empty while 'cert' is empty or nil. Typically a YAML/manifest that defines chain entries (intermediates) but omits the main override certificate.

Common situations: Operators pasting a full PEM bundle into 'chain' but forgetting the leaf CA in 'cert'; templates that split a PEM into the wrong fields; automation that strips the first certificate into a separate variable and ends up with an empty cert.

Understand the failure class

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/ad3f3a448b26182c. Report an issue: GitHub.