Tencent/WeKnora · error
URL has no hostname
Error message
URL has no hostname
What it means
ValidateURLForSSRF requires the parsed URL to carry a hostname. A URL like 'https:///path', 'file://', or a scheme-only string yields an empty parsed.Hostname() and is rejected with 'URL has no hostname'. Without a host the SSRF checks (IP-literal filtering, whitelist lookup) have nothing to evaluate, so the URL cannot be deemed safe.
Source
Thrown at internal/utils/security.go:1198
func ValidateURLForSSRF(rawURL string) error {
if rawURL == "" {
return nil // callers that require non-empty should validate separately
}
// Normalise: if no scheme, prepend https:// so url.Parse works correctly.
normalized := rawURL
if !strings.Contains(normalized, "://") {
normalized = "https://" + normalized
}
parsed, err := url.Parse(normalized)
if err != nil {
return fmt.Errorf("invalid URL: %w", err)
}
hostname := parsed.Hostname()
if hostname == "" {
return fmt.Errorf("URL has no hostname")
}
// A whitelist relaxes host/IP restrictions only. It must never turn other
// schemes (file://, gopher://, etc.) into valid outbound request targets.
scheme := strings.ToLower(parsed.Scheme)
if scheme != "http" && scheme != "https" {
return fmt.Errorf("invalid scheme: %s (only http/https allowed)", scheme)
}
// If the host is whitelisted, skip the heavy checks.
if IsSSRFWhitelisted(hostname) {
return nil
}
// Delegate to the full SSRF validation (uses the normalised URL).
if safe, reason := isSSRFSafeURL(normalized); !safe {
return fmt.Errorf("SSRF validation failed: %s", reason)
}View on GitHub (pinned to 988cbb0330)
Solutions
- Provide the full host in the endpoint: 'https://minio.example.com:9000' instead of 'https://:9000'
- Check that config substitution produced a non-empty hostname (echo the resolved value before deployment)
- Restore the missing double slash for scheme URLs ('https://host' not 'https:/host')
- Add a pre-flight url.Parse + Hostname() check in the caller to fail with a clearer config error
Example fix
// before
endpoint := "https://${OSS_HOST}" // OSS_HOST unset → https://
// after
host := os.Getenv("OSS_HOST")
if host == "" {
return fmt.Errorf("OSS_HOST must be set")
}
endpoint := "https://" + host Defensive patterns
Strategy: validation
Validate before calling
n := endpoint
if !strings.Contains(n, "://") { n = "https://" + n }
u, err := url.Parse(n)
if err != nil || u.Hostname() == "" {
return fmt.Errorf("endpoint %q has no hostname", endpoint)
} Type guard
func hasHostname(raw string) bool {
if !strings.Contains(raw, "://") { raw = "https://" + raw }
u, err := url.Parse(raw)
return err == nil && u.Hostname() != ""
} Prevention
- Always include scheme://host[:port] in endpoint configs — never scheme-only or port-only
- Verify templated hostnames (${VAR}) resolve before deploy
- Watch for the single-slash typo: https:/host collapses the host
- Log the resolved endpoint at startup to catch empty hosts early
When it happens
Trigger: Calling any storage client constructor or CheckObsConnectivity with a URL missing its host portion — e.g. 'https:///bucket', 'http://:9000', or an endpoint value that after normalization is just a scheme, or was mistyped as 'https:/myhost' (single slash collapses).
Common situations: Config where only the port was given, template variables expanding to empty hostnames ('https://${MISSING}/'), typo'd URLs with a single slash after the scheme, or copying 'https://' from a browser address bar with the domain trimmed.
Related errors
- invalid URL: %w
- unsafe MinIO endpoint: %w
- unsafe TOS endpoint: %w
- %w (for private deployments on internal networks, add the ho
- invalid qqbot api_base_url: %w (for private deployments, add
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/21ded480298097bc.
Report an issue: GitHub.