{"record":{"id":"c8b74cc4c6ea85cd","repo":"caddyserver/caddy","slug":"two-policies-with-same-match-criteria-have-conflic-c8b74c","errorCode":null,"errorMessage":"two policies with same match criteria have conflicting max protocol: %s vs. %s","messagePattern":"two policies with same match criteria have conflicting max protocol: (.+?) vs\\. (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"caddyconfig/httpcaddyfile/httptype.go","lineNumber":1296,"sourceCode":"\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\",\n\t\t\t\t\t\tcps[i].FallbackSNI, cps[j].FallbackSNI)\n\t\t\t\t}\n\t\t\t\tif cps[i].ProtocolMin != \"\" &&\n\t\t\t\t\tcps[j].ProtocolMin != \"\" &&\n\t\t\t\t\tcps[i].ProtocolMin != cps[j].ProtocolMin {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting min protocol: %s vs. %s\",\n\t\t\t\t\t\tcps[i].ProtocolMin, cps[j].ProtocolMin)\n\t\t\t\t}\n\t\t\t\tif cps[i].ProtocolMax != \"\" &&\n\t\t\t\t\tcps[j].ProtocolMax != \"\" &&\n\t\t\t\t\tcps[i].ProtocolMax != cps[j].ProtocolMax {\n\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting max protocol: %s vs. %s\",\n\t\t\t\t\t\tcps[i].ProtocolMax, cps[j].ProtocolMax)\n\t\t\t\t}\n\t\t\t\tif cps[i].CertSelection != nil && cps[j].CertSelection != nil {\n\t\t\t\t\t// merging fields other than AnyTag is not implemented\n\t\t\t\t\tif !reflect.DeepEqual(cps[i].CertSelection.SerialNumber, cps[j].CertSelection.SerialNumber) ||\n\t\t\t\t\t\t!reflect.DeepEqual(cps[i].CertSelection.SubjectOrganization, cps[j].CertSelection.SubjectOrganization) ||\n\t\t\t\t\t\tcps[i].CertSelection.PublicKeyAlgorithm != cps[j].CertSelection.PublicKeyAlgorithm ||\n\t\t\t\t\t\t!reflect.DeepEqual(cps[i].CertSelection.AllTags, cps[j].CertSelection.AllTags) {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting cert selections: %+v vs. %+v\",\n\t\t\t\t\t\t\tcps[i].CertSelection, cps[j].CertSelection)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// by now we've decided that we can merge the two -- we'll keep i and drop j\n\n\t\t\t\tif len(cps[i].ALPN) == 0 && len(cps[j].ALPN) > 0 {\n\t\t\t\t\tcps[i].ALPN = cps[j].ALPN\n\t\t\t\t}","sourceCodeStart":1278,"sourceCodeEnd":1314,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddyconfig/httpcaddyfile/httptype.go#L1278-L1314","documentation":"Two connection policies with the same match criteria declare different non-empty maximum TLS protocol versions. As with ProtocolMin, two different ceilings for the same matched connections cannot be reconciled and adaptation aborts.","triggerScenarios":"Site blocks sharing hostnames where one caps protocols at `tls1.2` (`tls { protocols tls1.0 tls1.2 }`) and another allows `tls1.3` — both survive to consolidation with identical matchers.","commonSituations":"Legacy-client compat block capping max version duplicated against a modern block for the same domain; version-cap snippets imported inconsistently.","solutions":["Unify the protocols ranges across all blocks for those hostnames","Remove the duplicate block","Prefer Caddy defaults unless a cap is required, and set it in exactly one place"],"exampleFix":"# before\nexample.com {\n  tls {\n    protocols tls1.2 tls1.2\n  }\n}\nexample.com {\n  tls {\n    protocols tls1.2 tls1.3\n  }\n}\n# after\nexample.com {\n  tls {\n    protocols tls1.2 tls1.3\n  }\n}","handlingStrategy":"validation","validationCode":"for h, maxs in group_protocolmax_by_host(sites).items():\n    assert len({m for m in maxs if m}) <= 1, f'conflicting protocol max for {h}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid version caps unless a legacy client needs them; then set in one place","Deduplicate site blocks","Validate merged configs with caddy adapt"],"tags":["caddy","tls","protocols","caddyfile","conflict"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}