caddyserver/caddy · error
two policies with same match criteria have conflicting curve
Error message
two policies with same match criteria have conflicting curves: %v vs. %v
What it means
Two TLS connection policies with the same match criteria declare different non-empty elliptic curve lists (`tls { curves ... }`). Caddy cannot merge two distinct curve preferences for connections both policies would govern, so adaptation stops and prints both lists.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1272
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",
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",View on GitHub (pinned to 50e54ee279)
Solutions
- Use the same curves list (or omit curves for secure defaults) in all blocks for those hostnames
- Deduplicate the site block
- Split genuinely different curve needs across different servers/ports
Example fix
# before
example.com {
tls {
curves x25519
}
}
example.com {
tls {
curves secp256r1
}
}
# after
example.com {
tls {
curves x25519 secp256r1
}
} Defensive patterns
Strategy: validation
Validate before calling
for h, lists in group_curves_by_host(sites).items():
assert len({tuple(l) for l in lists if l}) <= 1, f'conflicting curves for {h}' Prevention
- Omit curves to use safe defaults
- One tls snippet per hostname, imported everywhere
- Adapt-test after any curves tuning
When it happens
Trigger: Site blocks sharing hostnames where one sets `tls { curves x25519 }` and another sets `tls { curves secp256r1 x25519 }` on the same server, surviving consolidation with identical SNI matchers.
Common situations: Tuning curves for old-client compatibility on one copy of a duplicated site block, or applying a curves snippet inconsistently across imports of the same domain.
Related errors
- 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 defau
- two policies with same match criteria have conflicting fallb
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/df7598523ea2ec28.
Report an issue: GitHub.