gofiber/fiber · error

Domain pattern ' ' contains empty label at position

Error message

Domain pattern '%s' contains empty label at position %d

What it means

After splitting on '.', each label must be non-empty; an empty label indicates a malformed pattern such as "example..com" (double dot) or a leading/trailing dot. parseDomainPattern panics with the offending position to make the malformed label easy to locate.

Solutions

  1. Sanitize the pattern: remove empty segments with slices.DeleteFunc(strings.Split(p, "."), func(s string) bool { return s == ""}).
  2. Validate before registering: reject patterns containing ".." or starting with '.'.
  3. Trim and normalize input from config before using it as a domain pattern.

Example fix

// before
app.Domain("example..com")

// after
p := strings.Trim(p, ".")
if strings.Contains(p, "..") { return errors.New("malformed domain") }
app.Domain(p)
Defensive patterns

Strategy: validation

Validate before calling

// Reject malformed patterns with empty labels
func validateNoEmptyLabels(p string) error {
    if strings.HasPrefix(p, ".") || strings.HasSuffix(p, ".") || strings.Contains(p, "..") {
        return errors.New("malformed domain: empty label")
    }
    return nil
}

Prevention

When it happens

Trigger: Passing a pattern with two consecutive dots, or one that starts/ends with a dot after the trailing-dot normalization (e.g. ".example.com" or "example.com.").

Common situations: Concatenating segments with "." where one segment is empty; user input not trimmed; trailing-dot removal leaving an empty leading label; templating bug producing "..".

Related errors


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

Appendix: source

Thrown at domain.go:88

	}

	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)),
		numParts: len(parts),
	}

	for i, part := range parts {
		// Validate no empty labels (e.g., "example..com" is invalid)
		if part == "" {
			panic(fmt.Sprintf("Domain pattern '%s' contains empty label at position %d", pattern, i))
		}

		if part[0] == ':' {
			// Validate parameter name is not empty
			if len(part) == 1 {
				panic(fmt.Sprintf("Domain pattern '%s' contains empty parameter name at position %d", pattern, i))
			}
			paramName := part[1:]
			// Validate parameter name contains only ASCII-safe characters (a-z, A-Z, 0-9, underscore, hyphen).
			// Using explicit ASCII ranges rather than unicode.IsLetter/IsDigit to reject non-ASCII
			// characters that are invalid in DNS names.
			for _, ch := range paramName {
				if !isASCIIAlphanumeric(ch) && ch != '_' && ch != '-' {
					panic(fmt.Sprintf("Domain pattern '%s' contains invalid parameter name '%s' with character '%c'", pattern, paramName, ch))
				}
			}
			m.paramIdx = append(m.paramIdx, i)
			m.paramNames = append(m.paramNames, paramName) // preserve original case

View on GitHub (pinned to a105acad6c)