{"record":{"id":"a4bbfe77b1664a2e","repo":"gofiber/fiber","slug":"domain-pattern-s-contains-invalid-character-c","errorCode":null,"errorMessage":"Domain pattern '%s' contains invalid character '%c' in label '%s'","messagePattern":"Domain pattern '(.+?)' contains invalid character '%c' in label '(.+?)'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"domain.go","lineNumber":119,"sourceCode":"\t\t\t\tif !isASCIIAlphanumeric(ch) && ch != '_' && ch != '-' {\n\t\t\t\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' contains invalid parameter name '%s' with character '%c'\", pattern, paramName, ch))\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.paramIdx = append(m.paramIdx, i)\n\t\t\tm.paramNames = append(m.paramNames, paramName) // preserve original case\n\t\t\tm.parts[i] = part                              // keep \":param\" marker for matching\n\t\t} else {\n\t\t\t// Only lowercase constant labels (RFC 4343)\n\t\t\t// Enforce RFC 1035 per-label length limit (63 characters)\n\t\t\tif len(part) > 63 {\n\t\t\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' has label '%s' exceeding RFC 1035 limit of 63 characters (%d chars)\",\n\t\t\t\t\tpattern, part, len(part)))\n\t\t\t}\n\t\t\t// Validate label contains only valid ASCII domain characters (a-z, 0-9, hyphen).\n\t\t\tnormalized := utilsstrings.ToLower(part)\n\t\t\tfor _, ch := range normalized {\n\t\t\t\tif !isASCIIAlphanumeric(ch) && ch != '-' {\n\t\t\t\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' contains invalid character '%c' in label '%s'\", pattern, ch, part))\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.parts[i] = normalized\n\t\t}\n\t}\n\n\t// Check if the domain pattern has too many parameters\n\tif len(m.paramNames) > maxParams {\n\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' has %d parameters, which exceeds the maximum of %d\",\n\t\t\tpattern, len(m.paramNames), maxParams))\n\t}\n\n\treturn m\n}\n\n// match checks if a hostname matches the domain pattern.\n// It returns true if matched and a slice of parameter values (parallel to paramNames).\n// Uses a stack-allocated buffer to avoid heap allocation for typical domain names.","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/domain.go#L101-L137","documentation":"A constant label in a domain pattern contains a character that is not a lowercase letter, digit, or hyphen after lowercasing (RFC 4343 lowercasing is applied first). Underscores, dots, spaces, punctuation, and non-ASCII characters are rejected because they are invalid in DNS hostnames. Note this applies to constant labels only — ':param' names additionally permit '_'.","triggerScenarios":"Passing a domain pattern whose literal labels contain '_', '.', ' ', ':', '@', or non-ASCII characters, e.g. app.Use(\"foo_bar.example.com\", ...), app.Use(\"café.example.com\", ...), app.Use(\"foo!bar.com\", ...). The underscore in particular is allowed in param names but NOT in constant labels.","commonSituations":"Using snake_case hostnames (common in internal tooling/SRV records) as constant labels; pasting internationalized domain names without IDNA/punycode encoding; copy-paste introducing a trailing space or hidden unicode character; confusing param-name rules (which allow '_') with constant-label rules (which do not).","solutions":["Remove underscores and other punctuation from constant labels; use hyphens instead (e.g. 'foo-bar' not 'foo_bar').","Punycode-encode any internationalized label (xn--...) before putting it in the pattern.","If the underscore is intentional (e.g. _acme-challenge), route it as a ':param' segment or handle it outside the domain matcher."],"exampleFix":"// before\napp.Use(\"my_api.example.com\", handler)\n// after\napp.Use(\"my-api.example.com\", handler)","handlingStrategy":"validation","validationCode":"// validConstantLabel reports whether a literal label is DNS-safe (a-z0-9-).\nfunc validConstantLabel(lbl string) bool {\n    if lbl == \"\" || len(lbl) > 63 {\n        return false\n    }\n    for _, ch := range strings.ToLower(lbl) {\n        if !((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-') {\n            return false\n        }\n    }\n    return true\n}\n\nfor _, lbl := range strings.Split(domainPattern, \".\") {\n    if strings.HasPrefix(lbl, \":\") {\n        continue\n    }\n    if !validConstantLabel(lbl) {\n        return fmt.Errorf(\"invalid constant label %q\", lbl)\n    }\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        log.Fatalf(\"invalid domain label: %v\", r)\n    }\n}()\napp.Use(domainPattern, handler)","preventionTips":["Use hyphens, not underscores, in constant labels.","Punycode-encode internationalized labels (golang.org/x/net/idna).","Keep a linter/test that rejects '_' in any non-':param' label."],"tags":["routing","domain","dns","validation","startup"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}