caddyserver/caddy · error
two policies with same match criteria have conflicting clien
Error message
two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v
What it means
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.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1266
// if they have the same matcher, try to reconcile each field: either they must
// be identical, or we have to be able to combine them safely
if reflect.DeepEqual(cps[i].MatchersRaw, cps[j].MatchersRaw) {
if len(cps[i].ALPN) > 0 &&
len(cps[j].ALPN) > 0 &&
!reflect.DeepEqual(cps[i].ALPN, cps[j].ALPN) {
return nil, fmt.Errorf("two policies with same match criteria have conflicting ALPN: %v vs. %v",
cps[i].ALPN, cps[j].ALPN)
}
if len(cps[i].CipherSuites) > 0 &&
len(cps[j].CipherSuites) > 0 &&
!reflect.DeepEqual(cps[i].CipherSuites, cps[j].CipherSuites) {
return nil, fmt.Errorf("two policies with same match criteria have conflicting cipher suites: %v vs. %v",
cps[i].CipherSuites, cps[j].CipherSuites)
}
if cps[i].ClientAuthentication == nil &&
cps[j].ClientAuthentication != nil &&
!reflect.DeepEqual(cps[i].ClientAuthentication, cps[j].ClientAuthentication) {
return nil, fmt.Errorf("two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v",
cps[i].ClientAuthentication, cps[j].ClientAuthentication)
}
if len(cps[i].Curves) > 0 &&
len(cps[j].Curves) > 0 &&
!reflect.DeepEqual(cps[i].Curves, cps[j].Curves) {
return nil, fmt.Errorf("two policies with same match criteria have conflicting curves: %v vs. %v",
cps[i].Curves, cps[j].Curves)
}
if cps[i].DefaultSNI != "" &&
cps[j].DefaultSNI != "" &&
cps[i].DefaultSNI != cps[j].DefaultSNI {
return nil, fmt.Errorf("two policies with same match criteria have conflicting default SNI: %s vs. %s",
cps[i].DefaultSNI, cps[j].DefaultSNI)
}
if cps[i].FallbackSNI != "" &&
cps[j].FallbackSNI != "" &&
cps[i].FallbackSNI != cps[j].FallbackSNI {
return nil, fmt.Errorf("two policies with same match criteria have conflicting fallback SNI: %s vs. %s",View on GitHub (pinned to 50e54ee279)
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
Example fix
# before
api.example.com {
tls {
client_auth {
mode require_and_verify
trusted_ca_cert_file ca.pem
}
}
respond "mtls"
}
api.example.com {
respond "no-mtls"
}
# after
api.example.com {
tls {
client_auth {
mode require_and_verify
trusted_ca_cert_file ca.pem
}
}
respond "mtls"
} Defensive patterns
Strategy: validation
Validate before calling
# client_auth must be uniform per hostname
for h, cfgs in group_clientauth_by_host(sites).items():
assert all(c == cfgs[0] for c in cfgs), f'conflicting client_auth for {h}' Prevention
- Give mTLS endpoints their own subdomain
- Never duplicate a hostname across mtls and non-mtls blocks
- Keep client_auth in one snippet per domain
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- trust_pool module '%s' is not a certificate pool provider
- consolidating TLS connection policies for server %d: %v
- server listening on %v is HTTP, but attempts to configure TL
- two policies with same match criteria have conflicting ALPN:
- two policies with same match criteria have conflicting ciphe
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/08437095756d7fc4.
Report an issue: GitHub.