{"record":{"id":"2df1cba676182349","repo":"caddyserver/caddy","slug":"ca-s-has-a-nil-certificate-in-its-intermediate-ch","errorCode":null,"errorMessage":"CA %s has a nil certificate in its intermediate chain","messagePattern":"CA (.+?) has a nil certificate in its intermediate chain","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/capools.go","lineNumber":336,"sourceCode":"\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)\n\t\t\tcerts = append(certs, c)\n\t\t}\n\t}\n\tp.pool = caPool\n\tp.certs = certs\n\treturn nil\n}\n\n// Syntax:\n//\n//\ttrust_pool pki_intermediate [<ca_name>...] {\n//\t\tauthority <ca_name>...\n//\t}\n//\n// The 'authority' directive can be specified multiple times.\nfunc (pic *PKIIntermediateCAPool) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/capools.go#L318-L354","documentation":"While collecting IntermediateCertificateChain() from each CA for the pki_intermediate pool, a nil *x509.Certificate appeared in the chain. The pool refuses to add nil entries because they would poison the x509.CertPool used for client verification.","triggerScenarios":"A CA whose intermediate chain contains a nil slot — e.g. an intermediate certificate configured but not yet loaded/parsed (unreadable file, empty PEM), or a programmatically constructed CA whose chain array includes nil.","commonSituations":"pki CA configured with an `intermediate` block pointing to a missing or corrupt certificate file; storage-level partial writes to the internal CA's intermediate; custom embedding code that builds CA chains manually.","solutions":["Check the CA's `intermediate` sub-directive: the cert file must exist, be valid PEM, and be readable by Caddy.","Delete the internal CA's stored intermediate data so it is regenerated, then reload.","In embedded setups, ensure intermediate certificate slices contain no nil entries before provisioning caddytls."],"exampleFix":"# before\n{\n  pki {\n    ca custom {\n      intermediate { cert /etc/caddy/broken-intermediate.crt key /etc/caddy/intermediate.key }\n    }\n  }\n}\n\n# after\n{\n  pki {\n    ca custom {\n      intermediate { cert /etc/caddy/intermediate.crt key /etc/caddy/intermediate.key }\n    }\n  }\n}","handlingStrategy":"validation","validationCode":"// when building CA chains programmatically, reject nils before provisioning\nfor _, c := range chain {\n\tif c == nil {\n\t\treturn errors.New(\"intermediate chain contains nil certificate\")\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate intermediate PEM files with openssl before pointing the pki CA at them.","Keep intermediate cert+key files atomically deployed (write temp then rename).","Monitor Caddy's provisioning logs so partial CA state is caught on first load."],"tags":["caddy","caddytls","pki","certificate","nil-check"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}