{"record":{"id":"821f4efa4a48a7f7","repo":"caddyserver/caddy","slug":"pki-intermediate-ca-pool-requires-that-a-pki-app-i","errorCode":null,"errorMessage":"pki_intermediate CA pool requires that a PKI app is configured: %v","messagePattern":"pki_intermediate CA pool requires that a PKI app is configured: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/capools.go","lineNumber":320,"sourceCode":"\tpool  *x509.CertPool\n\tcerts []*x509.Certificate\n}\n\n// CaddyModule implements caddy.Module.\nfunc (PKIIntermediateCAPool) CaddyModule() caddy.ModuleInfo {\n\treturn caddy.ModuleInfo{\n\t\tID: \"tls.ca_pool.source.pki_intermediate\",\n\t\tNew: func() caddy.Module {\n\t\t\treturn new(PKIIntermediateCAPool)\n\t\t},\n\t}\n}\n\n// Loads the PKI app and loads the intermediate certificates into the certificate pool\nfunc (p *PKIIntermediateCAPool) Provision(ctx caddy.Context) error {\n\tpkiApp, err := ctx.AppIfConfigured(\"pki\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"pki_intermediate CA pool requires that a PKI app is configured: %v\", err)\n\t}\n\tpki := pkiApp.(*caddypki.PKI)\n\tfor _, caID := range p.Authority {\n\t\tc, err := pki.GetCA(ctx, caID)\n\t\tif err != nil || c == nil {\n\t\t\treturn fmt.Errorf(\"getting CA %s: %v\", caID, err)\n\t\t}\n\t\tp.ca = append(p.ca, c)\n\t}\n\n\tcaPool := x509.NewCertPool()\n\tvar certs []*x509.Certificate\n\tfor _, ca := range p.ca {\n\t\tfor _, c := range ca.IntermediateCertificateChain() {\n\t\t\tif c == nil {\n\t\t\t\treturn fmt.Errorf(\"CA %s has a nil certificate in its intermediate chain\", ca.ID)\n\t\t\t}\n\t\t\tcaPool.AddCert(c)","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/capools.go#L302-L338","documentation":"The `tls.ca_pool.source.pki_intermediate` module's Provision() calls ctx.AppIfConfigured(\"pki\") and errors when the PKI app is absent from the effective configuration. This pool trusts the intermediate certificates of Caddy's internal CAs, so the PKI app must be configured first.","triggerScenarios":"Using `trust_pool pki_intermediate` in the tls/client_auth config while no pki app block (global `pki` option or any `internal` issuer usage) exists in the same configuration.","commonSituations":"Adding client-auth with intermediate trust to a site that previously had no internal CA; splitting a config into snippets where the pki global option was left behind; test configs trimmed down to the minimum.","solutions":["Add the global `pki` option (or any usage of the `internal` issuer) so the PKI app is part of the config.","If internal PKI is not intended, replace pki_intermediate with `file`, `inline`, `storage`, or `system` trust pools.","Validate with `caddy validate --config Caddyfile` before deploy to catch it at load time."],"exampleFix":"# before\nexample.com {\n  tls { client_auth { trust_pool pki_intermediate } }\n}\n\n# after\n{\n  pki\n}\nexample.com {\n  tls { client_auth { trust_pool pki_intermediate } }\n}","handlingStrategy":"validation","validationCode":"// confirm pki app is configured before using pki_intermediate\nimport \"encoding/json\"\n\nfunc hasPKIApp(cfgJSON []byte) bool {\n\tvar cfg struct {\n\t\tApps map[string]json.RawMessage `json:\"apps\"`\n\t}\n\treturn json.Unmarshal(cfgJSON, &cfg) == nil\n\t\t&& func() bool { _, ok := cfg.Apps[\"pki\"]; return ok }()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat any `internal` issuer or pki_* trust pool usage as requiring the pki app; add the global pki option in the same change.","Validate adapted JSON in CI.","Document in repo README which snippets depend on the internal PKI."],"tags":["caddy","caddytls","pki","configuration","provisioning"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}