{"record":{"id":"1cd87cad2b04691f","repo":"caddyserver/caddy","slug":"converting-hostname-s-to-ascii-v","errorCode":null,"errorMessage":"converting hostname '%s' to ASCII: %v","messagePattern":"converting hostname '(.+?)' to ASCII: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/matchers.go","lineNumber":263,"sourceCode":"\t// iterate to merge multiple matchers into one\n\tfor d.Next() {\n\t\t*m = append(*m, d.RemainingArgs()...)\n\t\tif d.NextBlock(0) {\n\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","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/matchers.go#L245-L281","documentation":"MatchHost.Provision normalizes every `host` matcher entry with x/net/idna ToASCII before lowercasing and de-duplicating. If a host cannot be converted to punycode (malformed labels, bad characters, over-long labels), provisioning fails with this error naming the host.","triggerScenarios":"`host` matcher entries like \"exa mple.com\" (space), \"-leadinghyphen.example.com\", labels longer than 63 chars, empty labels (\"a..com\"), or characters the IDNA profile rejects such as underscores in strict profiles.","commonSituations":"Wildcard/certificate-san lists pasted with invisible whitespace; underscores in internal hostnames (some older Caddy versions tolerated `_` in host matchers, newer IDNA handling is stricter); U-labels with combining marks that fail validation.","solutions":["Correct the hostname: no spaces, no empty labels, labels ≤63 chars, valid characters only.","For internal names with underscores, test the exact entry against idna.ToASCII; if rejected, rename the service or match on a different field.","Quote and lint host lists when generating config to catch stray characters."],"exampleFix":"// before (Caddyfile)\n@ok host \"exa mple.com\"\n\n// after\n@ok host example.com","handlingStrategy":"validation","validationCode":"import \"golang.org/x/net/idna\"\n\nfunc validHostnames(hosts []string) bool {\n\tfor _, h := range hosts {\n\t\tif _, err := idna.ToASCII(h); err != nil {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["No spaces or empty labels; labels ≤63 chars.","Test underscore-bearing internal names with idna.ToASCII before shipping.","Trim and lint host lists from certificates/SANs."],"tags":["caddy","config","dns","idna","host-matcher"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}