{"record":{"id":"d59749cec25c9950","repo":"gofiber/fiber","slug":"domain-pattern-s-contains-invalid-parameter-nam","errorCode":null,"errorMessage":"Domain pattern '%s' contains invalid parameter name '%s' with character '%c'","messagePattern":"Domain pattern '(.+?)' contains invalid parameter name '(.+?)' with character '%c'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"domain.go","lineNumber":102,"sourceCode":"\n\tfor i, part := range parts {\n\t\t// Validate no empty labels (e.g., \"example..com\" is invalid)\n\t\tif part == \"\" {\n\t\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' contains empty label at position %d\", pattern, i))\n\t\t}\n\n\t\tif part[0] == ':' {\n\t\t\t// Validate parameter name is not empty\n\t\t\tif len(part) == 1 {\n\t\t\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' contains empty parameter name at position %d\", pattern, i))\n\t\t\t}\n\t\t\tparamName := part[1:]\n\t\t\t// Validate parameter name contains only ASCII-safe characters (a-z, A-Z, 0-9, underscore, hyphen).\n\t\t\t// Using explicit ASCII ranges rather than unicode.IsLetter/IsDigit to reject non-ASCII\n\t\t\t// characters that are invalid in DNS names.\n\t\t\tfor _, ch := range paramName {\n\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}","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/domain.go#L84-L120","documentation":"A domain-pattern label written as ':param' contains a character outside the allowed set [a-zA-Z0-9_-] (e.g. ':user.id', ':a/b', or a non-ASCII unicode letter). fiber/v3's domainMatcher rejects these at pattern-compile time because the captured value is interpolated into DNS-style matching and only ASCII-safe label characters are permitted. The check deliberately uses explicit ASCII ranges instead of unicode.IsLetter/IsDigit so non-ASCII letters (invalid in DNS names) are rejected.","triggerScenarios":"Calling any domain-based routing API that compiles a domain pattern (e.g. fiber.New().Use(\":user.example.com\", ...) or app.Domain(...)-style mounting) where any ':param' segment contains characters other than ASCII letters, digits, underscore, or hyphen — for instance ':user.name', ':café', ':a@b', or ':1st'.","commonSituations":"Copying a path-style ':param.param' or ':param[key]' Express syntax into a domain pattern; using internationalized/unicode label names; pasting a hostname fragment that contains '.', '/', or '@' inside what was meant to be a single parameter token.","solutions":["Restrict each ':param' name to ASCII letters, digits, underscore, and hyphen only; remove '.', '/', '@', spaces, and any non-ASCII character from the param token.","If you need nested segments, split them into separate labels (e.g. ':user.:example.com' with two params) rather than embedding '.' inside one param name.","Validate the pattern string with a regexp like ^:[A-Za-z0-9_-]+$ on each param token before passing it to the domain router."],"exampleFix":"// before\napp.Use(\":user.name.example.com\", handler)\n// after\napp.Use(\":user.:name.example.com\", handler)","handlingStrategy":"validation","validationCode":"// validParamToken reports whether a ':name' token is acceptable to the domain matcher.\nfunc validParamToken(name string) bool {\n    if name == \"\" {\n        return false\n    }\n    for _, ch := range name {\n        if !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||\n            (ch >= '0' && ch <= '9') || ch == '_' || ch == '-') {\n            return false\n        }\n    }\n    return true\n}\n\n// call before app.Use(domainPattern, ...):\nfor _, lbl := range strings.Split(strings.TrimSuffix(domainPattern, \".\"), \".\") {\n    if strings.HasPrefix(lbl, \":\") && !validParamToken(lbl[1:]) {\n        return fmt.Errorf(\"invalid domain param token %q\", lbl)\n    }\n}","typeGuard":null,"tryCatchPattern":"// Panics happen at app-construction time; wrap router setup in a bootstrap func\n// so a bad config aborts startup loudly instead of half-initializing the app.\nfunc buildRouter() (err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"router setup failed: %v\", r)\n        }\n    }()\n    app.Use(\":user.example.com\", handler)\n    return nil\n}","preventionTips":["Keep a single helper that constructs and validates domain patterns; never build pattern strings ad hoc.","Treat '.' as the only legal separator inside a domain pattern; never put '.', '/', '@', or unicode inside a ':param' name.","Add a unit test that feeds your generated patterns through the real domain matcher to catch bad tokens in CI."],"tags":["routing","domain","validation","startup"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}