caddyserver/caddy · error

no PEM keys specified

Error message

no PEM keys specified

What it means

StoragePool.Provision rejects a `tls.ca_pool.source.storage` trust pool whose PEMKeys list is empty. The storage pool reads certificate PEM files from a storage backend, so at least one storage key must be named.

Source

Thrown at modules/caddytls/capools.go:422

// Provision implements caddy.Provisioner.
func (ca *StoragePool) Provision(ctx caddy.Context) error {
	if ca.StorageRaw != nil {
		val, err := ctx.LoadModule(ca, "StorageRaw")
		if err != nil {
			return fmt.Errorf("loading storage module: %v", err)
		}
		cmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()
		if err != nil {
			return fmt.Errorf("creating storage configuration: %v", err)
		}
		ca.storage = cmStorage
	}
	if ca.storage == nil {
		ca.storage = ctx.Storage()
	}
	if len(ca.PEMKeys) == 0 {
		return fmt.Errorf("no PEM keys specified")
	}
	caPool := x509.NewCertPool()
	var certs []*x509.Certificate
	for _, caID := range ca.PEMKeys {
		bs, err := ca.storage.Load(ctx, caID)
		if err != nil {
			return fmt.Errorf("error loading cert '%s' from storage: %s", caID, err)
		}
		// Parse PEM to extract certificates
		pemData := bs
		for len(pemData) > 0 {
			var block *pem.Block
			block, pemData = pem.Decode(pemData)
			if block == nil {
				break
			}
			if block.Type != "CERTIFICATE" {
				continue

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Add at least one storage key / PEM path argument to the trust_pool storage block.
  2. If you intended no storage-based trust, remove the trust_pool storage block entirely.
  3. Validate config with `caddy validate` to catch empty blocks before reload.

Example fix

# before
trust_pool storage {
  trusted_ca_certs_pem
}

# after
trust_pool storage {
  trusted_ca_certs_pem certs/internal-ca-root.pem
}
Defensive patterns

Strategy: validation

Validate before calling

// for generated configs: skip emitting the block when empty
if len(pemKeys) == 0 {
	return nil // do not add a trust_pool storage source
}

Prevention

When it happens

Trigger: Configuring `trust_pool storage` with no `trusted_ca_certs_pem`/PEM key arguments (or an empty list after Caddyfile parsing / JSON with an empty array).

Common situations: Placeholder or half-written config blocks; snippets where the PEM list is templated to empty; JSON configs where the pem_keys array was dropped during refactoring.

Related errors


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