gofiber/fiber · error

Domain pattern cannot be empty

Error message

Domain pattern cannot be empty

What it means

parseDomainPattern normalizes the domain pattern (TrimSpace, then strips a trailing FQDN dot per RFC 3986) and rejects empty input. Domain routing requires at least one label, so an empty pattern is a caller bug caught at route registration.

Solutions

  1. Pass a non-empty domain string after trimming, e.g. "api.example.com".
  2. Validate the source config: if domain == "" { return error } before calling Domain APIs.
  3. Strip only the trailing dot yourself and ensure at least one label remains.

Example fix

// before
app.Domain(strings.Trim(cfg.Host, "."))  // "" when Host is unset

// after
host := strings.TrimSpace(cfg.Host)
if host == "" { return errors.New("host required") }
app.Domain(host)
Defensive patterns

Strategy: validation

Validate before calling

// Reject empty domain patterns before calling Domain APIs
func normalizeDomain(p string) (string, error) {
    p = strings.TrimSpace(p)
    p = strings.TrimRight(p, ".")
    if p == "" { return "", errors.New("empty domain pattern") }
    return p, nil
}

Prevention

When it happens

Trigger: Calling app.Use("", hostMiddleware) with a Domain constraint, or app.Domain("") or a domain pattern that becomes empty after trimming whitespace and trailing dots (e.g. "." or " ").

Common situations: Reading the domain from config/env that was unset; passing the result of strings.Trim that yielded empty; user input not validated before being used as a domain pattern.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/bab742972b8dd379. Report an issue: GitHub.

Appendix: source

Thrown at domain.go:63

// maxDomainParts defines the maximum number of domain labels allowed (e.g., sub.domain.example.com = 4 parts).
// This prevents DoS attacks from patterns or hostnames with excessive label counts.
// RFC 1035 suggests 127 labels max, but we use a more conservative limit to prevent memory exhaustion.
const maxDomainParts = 16

// parseDomainPattern parses a domain pattern like ":subdomain.example.com"
// into a domainMatcher. Parameter parts start with ":".
// Constant labels are lowercased per RFC 4343 (domain names are case-insensitive),
// but parameter names are preserved as-is so that DomainParam lookups work with
// the exact names the caller used (e.g., ":User" → param name "User").
func parseDomainPattern(pattern string) domainMatcher {
	pattern = utils.TrimSpace(pattern)
	// Trim trailing dot of a fully-qualified domain name (RFC 3986),
	// consistent with Fiber's own host normalization in Subdomains().
	pattern = utils.TrimRight(pattern, '.')

	// Validate pattern is not empty after trimming
	if pattern == "" {
		panic("Domain pattern cannot be empty")
	}

	// Enforce RFC 1035 total length limit on patterns
	if len(pattern) > 253 {
		panic(fmt.Sprintf("Domain pattern '%s' exceeds RFC 1035 maximum of 253 characters (%d chars)",
			pattern, len(pattern)))
	}

	parts := strings.Split(pattern, ".")

	// Prevent DoS from patterns with excessive label counts
	if len(parts) > maxDomainParts {
		panic(fmt.Sprintf("Domain pattern '%s' has %d parts, which exceeds the maximum of %d",
			pattern, len(parts), maxDomainParts))
	}

	m := domainMatcher{
		parts:    make([]string, len(parts)),

View on GitHub (pinned to a105acad6c)