{"record":{"id":"357696b14767be42","repo":"caddyserver/caddy","slug":"conflicting-config-for-client-authentication-trust","errorCode":null,"errorMessage":"conflicting config for client authentication trust CA","messagePattern":"conflicting config for client authentication trust CA","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/connpolicy.go","lineNumber":780,"sourceCode":"\tfor block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {\n\t\tif block.Type != \"CERTIFICATE\" {\n\t\t\treturn nil, fmt.Errorf(\"no CERTIFICATE pem block found in %s\", filename)\n\t\t}\n\t\tders = append(\n\t\t\tders,\n\t\t\tbase64.StdEncoding.EncodeToString(block.Bytes),\n\t\t)\n\t}\n\t// if we decoded nothing, return an error\n\tif len(ders) == 0 {\n\t\treturn nil, fmt.Errorf(\"no CERTIFICATE pem block found in %s\", filename)\n\t}\n\treturn ders, nil\n}\n\nfunc (clientauth *ClientAuthentication) provision(ctx caddy.Context) error {\n\tif len(clientauth.CARaw) > 0 && (len(clientauth.TrustedCACerts) > 0 || len(clientauth.TrustedCACertPEMFiles) > 0) {\n\t\treturn fmt.Errorf(\"conflicting config for client authentication trust CA\")\n\t}\n\n\t// convert all named file paths to inline\n\tif len(clientauth.TrustedCACertPEMFiles) > 0 {\n\t\tfor _, fpath := range clientauth.TrustedCACertPEMFiles {\n\t\t\tders, err := convertPEMFilesToDER(fpath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tclientauth.TrustedCACerts = append(clientauth.TrustedCACerts, ders...)\n\t\t}\n\t}\n\n\t// if we have TrustedCACerts explicitly set, create an 'inline' CA and return\n\tif len(clientauth.TrustedCACerts) > 0 {\n\t\tcaPool := InlineCAPool{\n\t\t\tTrustedCACerts: clientauth.TrustedCACerts,\n\t\t}","sourceCodeStart":762,"sourceCodeEnd":798,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/connpolicy.go#L762-L798","documentation":"ClientAuthentication.provision rejects configurations that specify both the 'ca' module (CARaw, e.g. an internal PKI CA provider) and one of trusted_ca_certs / trusted_ca_certs_file for the same connection policy. Both are ways to define the client trust CA, and Caddy refuses to guess which one wins.","triggerScenarios":"In JSON: setting both \"client_authentication\": {\"ca\": {...}} and \"trusted_ca_certs\" or \"trusted_ca_cert PEM files\" on the same policy. In Caddyfile: mixing the 'ca' subdirective with 'trusted_ca_cert' / 'trusted_ca_cert_file' inside a client_auth block.","commonSituations":"Migrating from static CA pinning to the internal CA module (or vice versa) and leaving the old directive behind; copying example configs that use both styles; layered config includes that each add one option.","solutions":["Pick ONE trust source: either the 'ca' module or the static cert list/files, and remove the other","If you merged two config fragments, diff your connection policy and delete the duplicate trust setting","Validate the config before deploy: caddy validate --config Caddyfile","If you genuinely need multiple trust anchors, put them all in one trust_ca bundle file and drop the 'ca' module"],"exampleFix":"# before\nclient_auth {\n  mode require_and_verify\n  ca internal\n  trusted_ca_cert_file /etc/caddy/ca.pem\n}\n\n# after\nclient_auth {\n  mode require_and_verify\n  trusted_ca_cert_file /etc/caddy/ca.pem\n}","handlingStrategy":"validation","validationCode":"// Reject conflicting client-auth trust config before provisioning\ntype connPolicyLike struct {\n\tClientAuthentication *struct {\n\t\tCA                    json.RawMessage `json:\"ca,omitempty\"`\n\t\tTrustedCACerts        []string        `json:\"trusted_ca_certs,omitempty\"`\n\t\tTrustedCACertPEMFiles []string        `json:\"trusted_ca_cert_pem_files,omitempty\"`\n\t}\n}\nfunc checkNoTrustConflict(p connPolicyLike) error {\n\tca := p.ClientAuthentication\n\tif ca == nil {\n\t\treturn nil\n\t}\n\tif len(ca.CA) > 0 && (len(ca.TrustedCACerts) > 0 || len(ca.TrustedCACertPEMFiles) > 0) {\n\t\treturn fmt.Errorf(\"either 'ca' module or trusted_ca_certs(_pem_files), not both\")\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt one convention per fleet (module CA or static bundle) and lint configs for the other","Treat 'caddy validate' as a required pre-deploy step","Keep client_auth sections in a single shared snippet/include rather than duplicating them"],"tags":["tls","client-auth","config-conflict","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}