{"record":{"id":"5464c0976624f717","repo":"caddyserver/caddy","slug":"no-sources-specified-for-combined-ca-pool","errorCode":null,"errorMessage":"no sources specified for combined CA pool","messagePattern":"no sources specified for combined CA pool","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/capools.go","lineNumber":852,"sourceCode":"\tsources []CA\n\tpool    *x509.CertPool\n\tcerts   []*x509.Certificate\n}\n\n// CaddyModule implements caddy.Module.\nfunc (CombinedCAPool) CaddyModule() caddy.ModuleInfo {\n\treturn caddy.ModuleInfo{\n\t\tID: \"tls.ca_pool.source.combined\",\n\t\tNew: func() caddy.Module {\n\t\t\treturn new(CombinedCAPool)\n\t\t},\n\t}\n}\n\n// Provision implements caddy.Provisioner.\nfunc (ccp *CombinedCAPool) Provision(ctx caddy.Context) error {\n\tif len(ccp.SourcesRaw) == 0 {\n\t\treturn fmt.Errorf(\"no sources specified for combined CA pool\")\n\t}\n\n\t// Load all source modules\n\tsources, err := ctx.LoadModule(ccp, \"SourcesRaw\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"loading CA pool sources: %v\", err)\n\t}\n\n\tcaPool := x509.NewCertPool()\n\tvar allCerts []*x509.Certificate\n\n\tfor _, src := range sources.([]any) {\n\t\tca, ok := src.(CA)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"source module is not a CA pool provider\")\n\t\t}\n\t\tccp.sources = append(ccp.sources, ca)\n","sourceCodeStart":834,"sourceCodeEnd":870,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/capools.go#L834-L870","documentation":"The `tls.ca_pool.source.combined` pool requires at least one nested CA pool source, and Provision() rejects a config with an empty SourcesRaw list. A combined pool with no sources would trust nothing, so it is treated as a configuration error.","triggerScenarios":"Configuring `trust_pool combined` with an empty body, or a JSON config where the sources array is absent/empty after templating or snippet expansion.","commonSituations":"Composable snippets that conditionally include sources but expand to none; placeholder blocks left in configs; automation generating empty combined pools.","solutions":["Add at least one source block (file, inline, pki_root, storage, system, http...) inside the combined pool.","If the pool is conditional in generated configs, skip emitting the combined block entirely when the source list is empty.","Run `caddy validate` to catch it before apply."],"exampleFix":"# before\ntrust_pool combined {\n}\n\n# after\ntrust_pool combined {\n  file /etc/caddy/roots.pem\n  system\n}","handlingStrategy":"validation","validationCode":"// generated configs: only emit combined pool when sources exist\nif len(sources) == 0 {\n\treturn nil // omit the combined trust pool entirely\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["`caddy validate` templated configs in CI.","Treat empty trust_pool combined blocks as a lint error.","Default generated configs to at least one explicit source (e.g. system)."],"tags":["caddy","caddytls","configuration","validation","combined-pool"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}