MHSanaei/3x-ui · error

invalid host %q

Error message

invalid host %q

What it means

NormalizeHost accepts bracketed IPv6 literals, any parseable IP, or hostnames matching a strict LDH pattern (alphanumeric segments joined by dots, labels starting/ending alphanumeric, total length ≤ 253). Anything else — underscores, spaces, protocol prefixes, IPv6 without brackets, labels >63 chars — fails with 'invalid host %q'.

Source

Thrown at internal/util/netsafe/netsafe.go:77

	}
	return nil, lastErr
}

var hostnamePattern = regexp.MustCompile(`^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$`)

func NormalizeHost(addr string) (string, error) {
	addr = strings.TrimSpace(addr)
	if addr == "" {
		return "", fmt.Errorf("address is required")
	}
	if strings.HasPrefix(addr, "[") && strings.HasSuffix(addr, "]") {
		addr = addr[1 : len(addr)-1]
	}
	if ip := net.ParseIP(addr); ip != nil {
		return ip.String(), nil
	}
	if len(addr) > 253 || !hostnamePattern.MatchString(addr) {
		return "", fmt.Errorf("invalid host %q", addr)
	}
	return addr, nil
}

View on GitHub (pinned to ad32144c42)

Solutions

  1. Pass host only — strip scheme and port before calling (e.g. u.Hostname() output).
  2. Replace underscores with hyphens in hostnames.
  3. Wrap IPv6 literals in brackets: [fe80::1].
  4. Shorten or fix >253-char or malformed labels; verify with `dig <host>` that the name is even legal.

Example fix

// before
host, err := netsafe.NormalizeHost("https://example.com:443") // invalid host

// after
u, _ := url.Parse("https://example.com:443")
host, err := netsafe.NormalizeHost(u.Hostname()) // "example.com"
Defensive patterns

Strategy: type-guard

Validate before calling

if _, err := netsafe.NormalizeHost(host); err != nil {
    return fmt.Errorf("fix address field: %w", err)
}

Type guard

func isPlausibleHost(s string) bool {
	s = strings.TrimSpace(s)
	if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") { return true }
	if net.ParseIP(s) != nil { return true }
	return len(s) <= 253 && !strings.ContainsAny(s, " :/@_") && !strings.Contains(s, "://")
}

Try / catch

host, err := netsafe.NormalizeHost(addr)
if err != nil {
    return fmt.Errorf("address %q must be a bare host or IP (no scheme/port): %w", addr, err)
}

Prevention

When it happens

Trigger: Passing 'my_host.example.com' (underscore), 'example.com:443' (port included), 'fe80::1' without brackets, 'https://example.com' (full URL), a >253-char name, or a label with leading/trailing hyphen.

Common situations: Users pasting a full URL or host:port into an address-only field; Windows machine names with underscores; forgetting brackets on IPv6; DNS names with wildcard '*' segments; copy-paste adding an invisible space or trailing dot variants.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/d5598423653bfdd3. Report an issue: GitHub.