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
- Pass host only — strip scheme and port before calling (e.g. u.Hostname() output).
- Replace underscores with hyphens in hostnames.
- Wrap IPv6 literals in brackets: [fe80::1].
- 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
- Store host and port in separate fields; never accept combined host:port in the address field.
- Strip scheme/port with u.Hostname() before persisting user URLs.
- Reject underscores and enforce bracketed IPv6 at input time.
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
- parse proxy url: %w
- unsupported proxy scheme %q
- address is required
- invalid node port %d
- download xray checksum: %w
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/d5598423653bfdd3.
Report an issue: GitHub.