{"id":"fc980bccbcebcf02","repo":"gofiber/fiber","slug":"domain-pattern-s-has-d-parts-which-exceeds-th","errorCode":null,"errorMessage":"Domain pattern '%s' has %d parts, which exceeds the maximum of %d","messagePattern":"Domain pattern '(.+?)' has (.+?) parts, which exceeds the maximum of (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"domain.go","lineNumber":76,"sourceCode":"\t// consistent with Fiber's own host normalization in Subdomains().\n\tpattern = utils.TrimRight(pattern, '.')\n\n\t// Validate pattern is not empty after trimming\n\tif pattern == \"\" {\n\t\tpanic(\"Domain pattern cannot be empty\")\n\t}\n\n\t// Enforce RFC 1035 total length limit on patterns\n\tif len(pattern) > 253 {\n\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' exceeds RFC 1035 maximum of 253 characters (%d chars)\",\n\t\t\tpattern, len(pattern)))\n\t}\n\n\tparts := strings.Split(pattern, \".\")\n\n\t// Prevent DoS from patterns with excessive label counts\n\tif len(parts) > maxDomainParts {\n\t\tpanic(fmt.Sprintf(\"Domain pattern '%s' has %d parts, which exceeds the maximum of %d\",\n\t\t\tpattern, len(parts), maxDomainParts))\n\t}\n\n\tm := domainMatcher{\n\t\tparts:    make([]string, len(parts)),\n\t\tnumParts: len(parts),\n\t}\n\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))","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/domain.go#L58-L94","documentation":"Panics from domain.go:76 when the pattern splits into more than maxDomainParts (16) dot-separated labels. The 16-label cap is a deliberate DoS guard below RFC 1035's 127-label theoretical max, preventing memory exhaustion from pathological patterns.","triggerScenarios":"app.Domain(\"a.b.c.d....\") with more than 16 labels; a pattern built by repeating \".x\" in a loop; deeply nested generated subdomains.","commonSituations":"Generated wildcard/tenant patterns with unbounded depth; malformed input fed from a database column; test fixtures with artificially deep domains.","solutions":["Reduce the pattern to 16 or fewer labels.","Validate len(strings.Split(pattern, \".\")) <= 16 before calling Domain().","Rearchitect over-deep tenant schemes to use fewer subdomain levels or path-based routing."],"exampleFix":"// before\napp.Domain(genDeepDomain(n)).Get(\"/\", h) // n > 16\n\n// after\npat := genDeepDomain(n)\nif len(strings.Split(pat, \".\")) > 16 {\n    return fmt.Errorf(\"domain pattern has too many labels\")\n}\napp.Domain(pat).Get(\"/\", h)","handlingStrategy":"validation","validationCode":"if len(strings.Split(pattern, \".\")) > 16 {\n    return fmt.Errorf(\"domain pattern exceeds 16 labels\")\n}\napp.Domain(pattern).Get(\"/\", h)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Bound the depth of generated subdomain patterns.","Reject over-deep tenant schemes at config load.","Prefer path-based routing for unbounded variability."],"tags":["routing","domain","validation","dos-protection","panic"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}