MHSanaei/3x-ui · warning
URL host is required
Error message
URL host is required
What it means
SanitizeHTTPURL requires a non-empty Host with a parseable hostname. It fires when the scheme is http(s) but url.Parse found no authority component — inputs like 'https:///path' (empty host), 'http://' (nothing at all), or 'https:/path' (single slash: url.Parse treats it as path-only on older Go stdlib shapes).
Source
Thrown at internal/web/service/url_safety.go:29
"github.com/mhsanaei/3x-ui/v3/internal/util/netsafe"
)
// SanitizeHTTPURL validates and normalizes an http(s) URL without resolving
// DNS. Use SanitizePublicHTTPURL at the point of an outbound request.
func SanitizeHTTPURL(raw string) (string, error) {
raw = strings.TrimSpace(raw)
if raw == "" {
return "", nil
}
u, err := url.Parse(raw)
if err != nil {
return "", err
}
if u.Scheme != "http" && u.Scheme != "https" {
return "", fmt.Errorf("unsupported URL scheme %q", u.Scheme)
}
if u.Host == "" || u.Hostname() == "" {
return "", fmt.Errorf("URL host is required")
}
clean := &url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: u.Path,
RawPath: u.RawPath,
RawQuery: u.RawQuery,
Fragment: u.Fragment,
}
return clean.String(), nil
}
// SanitizePublicHTTPURL validates and normalizes an http(s) URL, then blocks
// private/internal targets unless the caller explicitly allows them.
func SanitizePublicHTTPURL(raw string, allowPrivate bool) (string, error) {
clean, err := SanitizeHTTPURL(raw)
if err != nil || clean == "" {
return clean, errView on GitHub (pinned to ad32144c42)
Solutions
- Require and validate the host field at input time (non-empty, matches a hostname regex) before building the URL.
- Fix the concatenation site: check the host variable is non-empty before fmt.Sprintf("https://%s/...", host).
- Trim input — leading whitespace can make url.Parse put the whole string into Path.
Example fix
// before
url := fmt.Sprintf("https://%s/ping", host) // host == "" -> "https:///ping"
// after
if strings.TrimSpace(host) == "" {
return errors.New("host is required")
}
url := fmt.Sprintf("https://%s/ping", host) Defensive patterns
Strategy: validation
Validate before calling
// Build URLs only from a validated non-empty host
host := strings.TrimSpace(host)
if host == "" {
return errors.New("host is required")
}
target := "https://" + host + path Type guard
func hasHost(raw string) bool {
u, err := url.Parse(strings.TrimSpace(raw))
return err == nil && u.Hostname() != ""
} Try / catch
clean, err := service.SanitizeHTTPURL(raw)
if err != nil && strings.Contains(err.Error(), "host is required") {
// prompt user for the address; do not default to localhost
} Prevention
- Never fmt.Sprintf a scheme onto an unvalidated host variable.
- Trim and require non-empty host in form validation before submit.
When it happens
Trigger: Storing 'http://' + an empty address field; concatenation bugs like "http://" + host where host is empty; user typing 'https:/example.com' (missing slash).
Common situations: Frontend forms submitting before the user filled the address; templating/config code joining scheme and host where the host variable is empty; trailing-colon typos.
Related errors
- unsupported URL scheme %q
- invalid host %q
- download xray checksum: %w
- blocked private/internal address %s
- cannot resolve host %s: %w
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/f71c8528402c901d.
Report an issue: GitHub.