{"record":{"id":"338bbffdeecd9382","repo":"caddyserver/caddy","slug":"two-policies-with-same-match-criteria-have-conflic-338bbf","errorCode":null,"errorMessage":"two policies with same match criteria have conflicting min protocol: %s vs. %s","messagePattern":"two policies with same match criteria have conflicting min protocol: (.+?) vs\\. (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"caddyconfig/httpcaddyfile/httptype.go","lineNumber":1290,"sourceCode":"\t\t\t\t\treturn nil, fmt.Errorf(\"two policies with same match criteria have conflicting curves: %v vs. %v\",\n\t\t\t\t\t\tcps[i].Curves, cps[j].Curves)\n\t\t\t\t}\n\t\t\t\tif cps[i].DefaultSNI != \"\" &&\n\t\t\t\t\tcps[j].DefaultSNI != \"\" &&\n\t\t\t\t\tcps[i].DefaultSNI != cps[j].DefaultSNI {\n\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}","sourceCodeStart":1272,"sourceCodeEnd":1308,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/caddyconfig/httpcaddyfile/httptype.go#L1272-L1308","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nexample.com {\n  tls {\n    protocols tls1.3\n  }\n}\nexample.com {\n  tls {\n    protocols tls1.2\n  }\n}\n# after\nexample.com {\n  tls {\n    protocols tls1.2 tls1.3\n  }\n}","handlingStrategy":"validation","validationCode":"for h, mins in group_protocolmin_by_host(sites).items():\n    assert len({m for m in mins if m}) <= 1, f'conflicting protocol min for {h}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One protocols setting per hostname (snippet)","Delete old hardening blocks after writing new ones","Track tls config in one file, not scattered site definitions"],"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"}