caddyserver/caddy · error

loading intermediate cert: %v

Error message

loading intermediate cert: %v

What it means

CA.loadOrGenIntermediate reads the intermediate certificate PEM from storage (storageKeyIntermediateCert). A non-ErrNotExist error — backend failure, permissions, I/O fault — is wrapped as 'loading intermediate cert'. A clean not-found instead triggers intermediate generation, so this error means storage is present but failing to serve the object.

Source

Thrown at modules/caddypki/ca.go:350

	}
	rootKeyPEM, err := certmagic.PEMEncodePrivateKey(rootKey)
	if err != nil {
		return nil, nil, fmt.Errorf("encoding root key: %v", err)
	}
	err = ca.storage.Store(ca.ctx, ca.storageKeyRootKey(), rootKeyPEM)
	if err != nil {
		return nil, nil, fmt.Errorf("saving root key: %v", err)
	}

	return rootCert, rootKey, nil
}

func (ca CA) loadOrGenIntermediate(rootCert *x509.Certificate, rootKey crypto.Signer) (interCertChain []*x509.Certificate, interKey crypto.Signer, err error) {
	var interCert *x509.Certificate
	interCertPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyIntermediateCert())
	if err != nil {
		if !errors.Is(err, fs.ErrNotExist) {
			return nil, nil, fmt.Errorf("loading intermediate cert: %v", err)
		}

		// TODO: should we require that all or none of the assets are required before overwriting anything?
		interCert, interKey, err = ca.genIntermediate(rootCert, rootKey)
		if err != nil {
			return nil, nil, fmt.Errorf("generating new intermediate cert: %v", err)
		}

		interCertChain = append(interCertChain, interCert)
	}

	if len(interCertChain) == 0 {
		interCertChain, err = pemDecodeCertificateChain(interCertPEM)
		if err != nil {
			return nil, nil, fmt.Errorf("decoding intermediate certificate PEM: %v", err)
		}
	}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Repair read access to the storage location and confirm the intermediate object is present and readable.
  2. Restore backend connectivity/credentials for custom storage, then restart.
  3. Validate the object is intact (openssl x509 -noout); if corrupt, delete the intermediate cert+key objects only (keep root) so Caddy regenerates the intermediate signed by the existing root.
  4. Point storage at a writable, healthy location if the backend is unreliable.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-start readability check for the intermediate object (skip if absent = OK)
if _, err := os.ReadFile(caDir + "/intermediate.crt"); err != nil && !errors.Is(err, fs.ErrNotExist) {
    log.Fatalf("storage failing for intermediate cert: %v", err)
}

Try / catch

// transient backend failures: one bounded retry, then fail with context
if strings.Contains(err.Error(), "loading intermediate cert") {
    if err2 := retryOnce(startCaddy, cfg); err2 != nil { return fmt.Errorf("storage failing: %w", err2) }
}

Prevention

When it happens

Trigger: storage.Load for the intermediate cert errors with something other than fs.ErrNotExist: unreadable file, custom storage backend outage, corrupted storage index. Happens whenever a CA loads an existing intermediate (normal subsequent startups) in the default (non-external-intermediate, non-sign_with_root) configuration.

Common situations: Service user lacking read permission on storage/caddy/pki/<id>/ca/intermediate.crt; Redis/consul/S3 briefly down at boot; migrated storage where the object metadata broke.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/fec7e71c2e64037f. Report an issue: GitHub.