{"record":{"id":"aefd16af0e42732a","repo":"caddyserver/caddy","slug":"no-pem-keys-specified","errorCode":null,"errorMessage":"no PEM keys specified","messagePattern":"no PEM keys specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/capools.go","lineNumber":422,"sourceCode":"\n// Provision implements caddy.Provisioner.\nfunc (ca *StoragePool) Provision(ctx caddy.Context) error {\n\tif ca.StorageRaw != nil {\n\t\tval, err := ctx.LoadModule(ca, \"StorageRaw\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"loading storage module: %v\", err)\n\t\t}\n\t\tcmStorage, err := val.(caddy.StorageConverter).CertMagicStorage()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating storage configuration: %v\", err)\n\t\t}\n\t\tca.storage = cmStorage\n\t}\n\tif ca.storage == nil {\n\t\tca.storage = ctx.Storage()\n\t}\n\tif len(ca.PEMKeys) == 0 {\n\t\treturn fmt.Errorf(\"no PEM keys specified\")\n\t}\n\tcaPool := x509.NewCertPool()\n\tvar certs []*x509.Certificate\n\tfor _, caID := range ca.PEMKeys {\n\t\tbs, err := ca.storage.Load(ctx, caID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error loading cert '%s' from storage: %s\", caID, err)\n\t\t}\n\t\t// Parse PEM to extract certificates\n\t\tpemData := bs\n\t\tfor len(pemData) > 0 {\n\t\t\tvar block *pem.Block\n\t\t\tblock, pemData = pem.Decode(pemData)\n\t\t\tif block == nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif block.Type != \"CERTIFICATE\" {\n\t\t\t\tcontinue","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/capools.go#L404-L440","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Add at least one storage key / PEM path argument to the trust_pool storage block.","If you intended no storage-based trust, remove the trust_pool storage block entirely.","Validate config with `caddy validate` to catch empty blocks before reload."],"exampleFix":"# before\ntrust_pool storage {\n  trusted_ca_certs_pem\n}\n\n# after\ntrust_pool storage {\n  trusted_ca_certs_pem certs/internal-ca-root.pem\n}","handlingStrategy":"validation","validationCode":"// for generated configs: skip emitting the block when empty\nif len(pemKeys) == 0 {\n\treturn nil // do not add a trust_pool storage source\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always run `caddy validate` on templated configs before applying.","Treat empty trust pool blocks as lint errors in config reviews.","When snippets parameterize PEM lists, default them to a required value rather than empty."],"tags":["caddy","caddytls","storage","configuration","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}