{"record":{"id":"480b9180d841c465","repo":"caddyserver/caddy","slug":"host-at-index-d-is-repeated-at-index-d-s","errorCode":null,"errorMessage":"host at index %d is repeated at index %d: %s","messagePattern":"host at index (.+?) is repeated at index (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"modules/caddyhttp/matchers.go","lineNumber":267,"sourceCode":"\t\t\treturn d.Err(\"malformed host matcher: blocks are not supported\")\n\t\t}\n\t}\n\treturn nil\n}\n\n// Provision sets up and validates m, including making it more efficient for large lists.\nfunc (m MatchHost) Provision(_ caddy.Context) error {\n\t// check for duplicates; they are nonsensical and reduce efficiency\n\t// (we could just remove them, but the user should know their config is erroneous)\n\tseen := make(map[string]int, len(m))\n\tfor i, host := range m {\n\t\tasciiHost, err := idna.ToASCII(host)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"converting hostname '%s' to ASCII: %v\", host, err)\n\t\t}\n\t\tnormalizedHost := strings.ToLower(asciiHost)\n\t\tif firstI, ok := seen[normalizedHost]; ok {\n\t\t\treturn fmt.Errorf(\"host at index %d is repeated at index %d: %s\", firstI, i, host)\n\t\t}\n\t\t// Normalize exact hosts for standardized comparison in large-list fastpath later on.\n\t\t// Keep wildcards/placeholders untouched.\n\t\tif m.fuzzy(asciiHost) {\n\t\t\tm[i] = asciiHost\n\t\t} else {\n\t\t\tm[i] = normalizedHost\n\t\t}\n\t\tseen[normalizedHost] = i\n\t}\n\n\tif m.large() {\n\t\t// sort the slice lexicographically, grouping \"fuzzy\" entries (wildcards and placeholders)\n\t\t// at the front of the list; this allows us to use binary search for exact matches, which\n\t\t// we have seen from experience is the most common kind of value in large lists; and any\n\t\t// other kinds of values (wildcards and placeholders) are grouped in front so the linear\n\t\t// search should find a match fairly quickly\n\t\tsort.Slice(m, func(i, j int) bool {","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/matchers.go#L249-L285","documentation":"MatchHost.Provision lowercases and ASCII-normalizes each host, then rejects duplicates — they are nonsensical in a matcher and would only slow down matching. The error reports the first index, the repeat index, and the host string. Case differences and unicode/punycode forms count as duplicates because normalization happens first.","triggerScenarios":"host list containing \"Example.com\" and \"example.com\"; \"exämple.com\" and its punycode \"xn--exmple-cua.com\"; the same name twice from a copy-paste.","commonSituations":"Config assembled from multiple team snippets; case-inconsistent DNS names in docs; unicode vs punycode duplicates after IDNA normalization; automated configs that append hosts without dedup.","solutions":["Delete the duplicate entry reported at the second index.","Deduplicate and lowercase host lists in your config-generation step.","Remember the matcher is already case-insensitive — one canonical spelling suffices."],"exampleFix":"// before (Caddyfile)\n@a host example.com Example.com\n\n// after\n@a host example.com","handlingStrategy":"validation","validationCode":"import (\n\t\"strings\"\n\t\"golang.org/x/net/idna\"\n)\n\nfunc noDuplicateHosts(hosts []string) bool {\n\tseen := map[string]bool{}\n\tfor _, h := range hosts {\n\t\ta, err := idna.ToASCII(h)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tk := strings.ToLower(a)\n\t\tif seen[k] {\n\t\t\treturn false\n\t\t}\n\t\tseen[k] = true\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate and lowercase host lists before generating config.","Remember unicode and punycode forms of the same name collide.","The matcher is case-insensitive already; one spelling is enough."],"tags":["caddy","config","duplicates","host-matcher","idna"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}