{"record":{"id":"08437095756d7fc4","repo":"caddyserver/caddy","slug":"two-policies-with-same-match-criteria-have-conflic-084370","errorCode":null,"errorMessage":"two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v","messagePattern":"two policies with same match criteria have conflicting client auth configuration: %\\+v vs\\. %\\+v","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"caddyconfig/httpcaddyfile/httptype.go","lineNumber":1266,"sourceCode":"\t\t\t// if they have the same matcher, try to reconcile each field: either they must\n\t\t\t// be identical, or we have to be able to combine them safely\n\t\t\tif reflect.DeepEqual(cps[i].MatchersRaw, cps[j].MatchersRaw) {\n\t\t\t\tif len(cps[i].ALPN) > 0 &&\n\t\t\t\t\tlen(cps[j].ALPN) > 0 &&\n\t\t\t\t\t!reflect.DeepEqual(cps[i].ALPN, cps[j].ALPN) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting ALPN: %v vs. %v\",\n\t\t\t\t\t\tcps[i].ALPN, cps[j].ALPN)\n\t\t\t\t}\n\t\t\t\tif len(cps[i].CipherSuites) > 0 &&\n\t\t\t\t\tlen(cps[j].CipherSuites) > 0 &&\n\t\t\t\t\t!reflect.DeepEqual(cps[i].CipherSuites, cps[j].CipherSuites) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting cipher suites: %v vs. %v\",\n\t\t\t\t\t\tcps[i].CipherSuites, cps[j].CipherSuites)\n\t\t\t\t}\n\t\t\t\tif cps[i].ClientAuthentication == nil &&\n\t\t\t\t\tcps[j].ClientAuthentication != nil &&\n\t\t\t\t\t!reflect.DeepEqual(cps[i].ClientAuthentication, cps[j].ClientAuthentication) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v\",\n\t\t\t\t\t\tcps[i].ClientAuthentication, cps[j].ClientAuthentication)\n\t\t\t\t}\n\t\t\t\tif len(cps[i].Curves) > 0 &&\n\t\t\t\t\tlen(cps[j].Curves) > 0 &&\n\t\t\t\t\t!reflect.DeepEqual(cps[i].Curves, cps[j].Curves) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting curves: %v vs. %v\",\n\t\t\t\t\t\tcps[i].Curves, cps[j].Curves)\n\t\t\t\t}\n\t\t\t\tif cps[i].DefaultSNI != \"\" &&\n\t\t\t\t\tcps[j].DefaultSNI != \"\" &&\n\t\t\t\t\tcps[i].DefaultSNI != cps[j].DefaultSNI {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting default SNI: %s vs. %s\",\n\t\t\t\t\t\tcps[i].DefaultSNI, cps[j].DefaultSNI)\n\t\t\t\t}\n\t\t\t\tif cps[i].FallbackSNI != \"\" &&\n\t\t\t\t\tcps[j].FallbackSNI != \"\" &&\n\t\t\t\t\tcps[i].FallbackSNI != cps[j].FallbackSNI {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting fallback SNI: %s vs. %s\",","sourceCodeStart":1248,"sourceCodeEnd":1284,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddyconfig/httpcaddyfile/httptype.go#L1248-L1284","documentation":"Two connection policies matching the same SNI criteria disagree on client authentication: one has ClientAuthentication nil (no client cert requirements) while the other defines one. Whether a client certificate is required is not mergeable, so adaptation fails showing both configurations with %+v.","triggerScenarios":"One site block for a hostname using plain `tls` and another block for the same hostname (or an overlapping SNI set) using `tls { client_auth { ... } }` — after consolidation both policies remain with the same matchers but incompatible client auth settings.","commonSituations":"Adding mTLS to one path of a domain while another block for the same domain lacks it, duplicating a site for staging/prod with the same name but only one requiring client certs, or a global client_auth policy overlapping a site without one.","solutions":["Move client_auth to a site block keyed on a distinct hostname/subdomain so its SNI matcher differs","Apply the same client_auth block to every site sharing the hostname","Drop the plain-TLS duplicate block so a single policy covers the name"],"exampleFix":"# before\napi.example.com {\n  tls {\n    client_auth {\n      mode require_and_verify\n      trusted_ca_cert_file ca.pem\n    }\n  }\n  respond \"mtls\"\n}\napi.example.com {\n  respond \"no-mtls\"\n}\n# after\napi.example.com {\n  tls {\n    client_auth {\n      mode require_and_verify\n      trusted_ca_cert_file ca.pem\n    }\n  }\n  respond \"mtls\"\n}","handlingStrategy":"validation","validationCode":"# client_auth must be uniform per hostname\nfor h, cfgs in group_clientauth_by_host(sites).items():\n    assert all(c == cfgs[0] for c in cfgs), f'conflicting client_auth for {h}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give mTLS endpoints their own subdomain","Never duplicate a hostname across mtls and non-mtls blocks","Keep client_auth in one snippet per domain"],"tags":["caddy","tls","mtls","client-auth","caddyfile"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}