caddyserver/caddy · error
two policies with same match criteria have conflicting min p
Error message
two policies with same match criteria have conflicting min protocol: %s vs. %s
What it means
Two TLS connection policies with the same match criteria declare different non-empty minimum TLS protocol versions (`tls { protocols <min> [<max>] }`). The adapter refuses to pick between two minimums for the same connections.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1290
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",
cps[i].FallbackSNI, cps[j].FallbackSNI)
}
if cps[i].ProtocolMin != "" &&
cps[j].ProtocolMin != "" &&
cps[i].ProtocolMin != cps[j].ProtocolMin {
return nil, fmt.Errorf("two policies with same match criteria have conflicting min protocol: %s vs. %s",
cps[i].ProtocolMin, cps[j].ProtocolMin)
}
if cps[i].ProtocolMax != "" &&
cps[j].ProtocolMax != "" &&
cps[i].ProtocolMax != cps[j].ProtocolMax {
return nil, fmt.Errorf("two policies with same match criteria have conflicting max protocol: %s vs. %s",
cps[i].ProtocolMax, cps[j].ProtocolMax)
}
if cps[i].CertSelection != nil && cps[j].CertSelection != nil {
// merging fields other than AnyTag is not implemented
if !reflect.DeepEqual(cps[i].CertSelection.SerialNumber, cps[j].CertSelection.SerialNumber) ||
!reflect.DeepEqual(cps[i].CertSelection.SubjectOrganization, cps[j].CertSelection.SubjectOrganization) ||
cps[i].CertSelection.PublicKeyAlgorithm != cps[j].CertSelection.PublicKeyAlgorithm ||
!reflect.DeepEqual(cps[i].CertSelection.AllTags, cps[j].CertSelection.AllTags) {
return nil, fmt.Errorf("two policies with same match criteria have conflicting cert selections: %+v vs. %+v",
cps[i].CertSelection, cps[j].CertSelection)
}
}View on GitHub (pinned to 50e54ee279)
Solutions
- Use one identical protocols setting for all blocks sharing the hostnames
- Delete the duplicated site/tls block
- Raise the protocol floor globally via site policy consistently, or drop it to use defaults
Example fix
# before
example.com {
tls {
protocols tls1.3
}
}
example.com {
tls {
protocols tls1.2
}
}
# after
example.com {
tls {
protocols tls1.2 tls1.3
}
} Defensive patterns
Strategy: validation
Validate before calling
for h, mins in group_protocolmin_by_host(sites).items():
assert len({m for m in mins if m}) <= 1, f'conflicting protocol min for {h}' Prevention
- One protocols setting per hostname (snippet)
- Delete old hardening blocks after writing new ones
- Track tls config in one file, not scattered site definitions
When it happens
Trigger: One site block for a hostname specifying `tls { protocols tls1.3 }` and another block for the same hostname specifying `tls { protocols tls1.2 }` — both policies reach consolidation with equal matchers but different ProtocolMin.
Common situations: Hardening one copy of a duplicated site to TLS 1.3 while the duplicate keeps tls1.2, or a hardening snippet applied to a site that already had its own protocols line.
Related errors
- two policies with same match criteria have conflicting max p
- 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
- two policies with same match criteria have conflicting curve
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/338bbffdeecd9382.
Report an issue: GitHub.