caddyserver/caddy · error
recombining SNI matchers: %v
Error message
recombining SNI matchers: %v
What it means
While consolidating connection policies, two policies with equal settings and positionally compatible SNI matchers were being merged by concatenating their MatchServerName lists; re-marshaling the combined list to JSON failed. This is essentially an internal serialization failure of data the adapter itself produced.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1236
// as a special case, if there are adjacent TLS conn policies that are identical except
// by their matchers, and the matchers are specifically just ServerName ("sni") matchers
// (by far the most common), we can combine them into a single policy
if i == j-1 && len(cps[i].MatchersRaw) == 1 && len(cps[j].MatchersRaw) == 1 {
if iSNIMatcherJSON, ok := cps[i].MatchersRaw["sni"]; ok {
if jSNIMatcherJSON, ok := cps[j].MatchersRaw["sni"]; ok {
// position of policies and the matcher criteria check out; if settings are
// the same, then we can combine the policies; we have to unmarshal and
// remarshal the matchers though
if cps[i].SettingsEqual(*cps[j]) {
var iSNIMatcher caddytls.MatchServerName
if err := json.Unmarshal(iSNIMatcherJSON, &iSNIMatcher); err == nil {
var jSNIMatcher caddytls.MatchServerName
if err := json.Unmarshal(jSNIMatcherJSON, &jSNIMatcher); err == nil {
iSNIMatcher = append(iSNIMatcher, jSNIMatcher...)
cps[i].MatchersRaw["sni"], err = json.Marshal(iSNIMatcher)
if err != nil {
return nil, fmt.Errorf("recombining SNI matchers: %v", err)
}
cps = slices.Delete(cps, j, j+1)
i--
break
}
}
}
}
}
}
// 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",View on GitHub (pinned to 50e54ee279)
Solutions
- If you use a custom adapter/plugin, ensure `sni` matchers in MatchersRaw are valid JSON arrays of strings
- Update Caddy — internal marshaling bugs of this kind get fixed upstream
- Reproduce with `caddy adapt --pretty` on a minimal config to identify which plugin mangles the matchers
Defensive patterns
Strategy: try-catch
Try / catch
if err := json.Marshal(iSNIMatcher); err != nil {
// internal path: report upstream with config that reproduces it
return nil, fmt.Errorf("recombining SNI matchers: %w", err)
} Prevention
- Keep Caddy updated; this is an internal marshaling path
- If injecting policy matchers programmatically, always emit []string JSON for sni
- Add a unit test that round-trips MatchersRaw through Unmarshal/Marshal
When it happens
Trigger: consolidateConnPolicies finds cps[i] and cps[j] with SettingsEqual and mergeable SNI matchers, unmarshals both `sni` matcher JSON blobs into caddytls.MatchServerName, appends them, and json.Marshal of the combined slice errors — in practice only reachable if the MatchersRaw['sni'] payload is not what the adapter expects (e.g. third-party code injected malformed matcher JSON).
Common situations: Almost never seen with a stock Caddyfile; can occur when a plugin or custom adapter pre-populates or mutates connection policy MatchersRaw with invalid SNI matcher JSON before consolidation runs.
Related errors
- not a valid big integer: %s
- getting tls app: %v
- loading certificates with 'automate' requires array of strin
- missing 'req' argument
- unsupported type
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/23156854305ca09f.
Report an issue: GitHub.