caddyserver/caddy · error

pki_root CA pool requires that a PKI app is configured: %v

Error message

pki_root CA pool requires that a PKI app is configured: %v

What it means

The `tls.ca_pool.source.pki_root` module's Provision() calls ctx.AppIfConfigured("pki"), which errors when the PKI app is not present in the effective Caddy configuration. The pki_root trust pool reads root certificates from Caddy's internal PKI app, so that app must be configured (usually via the `pki` global option or any `internal` issuer usage) before this pool can be provisioned.

Source

Thrown at modules/caddytls/capools.go:235

	pool  *x509.CertPool
	certs []*x509.Certificate
}

// CaddyModule implements caddy.Module.
func (PKIRootCAPool) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID: "tls.ca_pool.source.pki_root",
		New: func() caddy.Module {
			return new(PKIRootCAPool)
		},
	}
}

// Loads the PKI app and load the root certificates into the certificate pool
func (p *PKIRootCAPool) Provision(ctx caddy.Context) error {
	pkiApp, err := ctx.AppIfConfigured("pki")
	if err != nil {
		return fmt.Errorf("pki_root CA pool requires that a PKI app is configured: %v", err)
	}
	pki := pkiApp.(*caddypki.PKI)
	for _, caID := range p.Authority {
		c, err := pki.GetCA(ctx, caID)
		if err != nil || c == nil {
			return fmt.Errorf("getting CA %s: %v", caID, err)
		}
		p.ca = append(p.ca, c)
	}

	caPool := x509.NewCertPool()
	var certs []*x509.Certificate
	for _, ca := range p.ca {
		rootCert := ca.RootCertificate()
		if rootCert == nil {
			return fmt.Errorf("CA %s has no root certificate", ca.ID)
		}
		caPool.AddCert(rootCert)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Add a `pki` global option block (or a site/issuer that instantiates the PKI app) to the config, e.g. `{ pki { ca local { name "My Local CA" } } }`.
  2. If you do not want Caddy's internal PKI, switch the trust pool to `file`, `inline`, `storage`, or `system` instead of `pki_root`.
  3. Verify the config JSON contains a top-level `"apps"."pki"` object before applying (`caddy adapt` then inspect).

Example fix

# before
example.com {
  tls {
    client_auth {
      trust_pool pki_root
    }
  }
}

# after
{
  pki {
    ca local {
      name "Local CA"
    }
  }
}
example.com {
  tls {
    client_auth {
      trust_pool pki_root
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// before applying config, confirm the pki app is present
import "encoding/json"

func hasPKIApp(cfgJSON []byte) bool {
	var cfg struct {
		Apps map[string]json.RawMessage `json:"apps"`
	}
	if err := json.Unmarshal(cfgJSON, &cfg); err != nil {
		return false
	}
	_, ok := cfg.Apps["pki"]
	return ok
}

Prevention

When it happens

Trigger: Configuring `trust_pool pki_root` (with one or more `ca <id>` entries) in a Caddyfile or JSON config where no PKI app block exists — e.g. no `pki` global option and no site using the `internal` issuer, or the pki app block was removed/renamed while the trust pool remained.

Common situations: Copying a client-auth snippet that references pki_root into a minimal test config; upgrading/restructuring a config where the internal CA setup was dropped; using a named CA (e.g. `ca custom`) that was never declared in the pki app.

Related errors


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