larksuite/cli · error

URL host is required

Error message

URL host is required

What it means

resolveDownloadHost normalizes the URL host and requires a non-empty value before performing DNS lookups for SSRF checks. An empty host means the URL had no authority component (or only a fragment/query), so no target can be resolved. Called by ValidateDownloadSourceURL and RoundTrip.

Source

Thrown at internal/validate/url.go:98

// ValidateDownloadSourceURL validates a download URL and blocks local/internal targets.
func ValidateDownloadSourceURL(ctx context.Context, rawURL string) error {
	u, err := url.Parse(rawURL)
	if err != nil || u == nil {
		return fmt.Errorf("invalid URL")
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return fmt.Errorf("only http/https URLs are supported")
	}
	_, err = resolveDownloadHost(ctx, u.Hostname(), net.DefaultResolver.LookupIP)
	return err
}

type downloadLookupIPFunc func(context.Context, string, string) ([]net.IP, error)

func resolveDownloadHost(ctx context.Context, rawHost string, lookupIP downloadLookupIPFunc) ([]net.IP, error) {
	host := strings.TrimSpace(strings.ToLower(rawHost))
	if host == "" {
		return nil, fmt.Errorf("URL host is required")
	}
	if host == "localhost" || strings.HasSuffix(host, ".localhost") {
		return nil, fmt.Errorf("local/internal host is not allowed")
	}
	if ip := net.ParseIP(host); ip != nil {
		if isRestrictedDownloadIP(ip) {
			return nil, fmt.Errorf("local/internal host is not allowed")
		}
		return []net.IP{ip}, nil
	}
	if lookupIP == nil {
		lookupIP = net.DefaultResolver.LookupIP
	}
	ips, err := lookupIP(ctx, "ip", host)
	if err != nil {
		return nil, fmt.Errorf("failed to resolve host")
	}
	if len(ips) == 0 {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Include the full host in the URL: https://example.com/path, not https:///path.
  2. Verify any templated/host variable was actually set before expansion.
  3. Re-copy the URL from the original source in full.
  4. Validate locally: `python3 -c "import urllib.parse,sys; print(urllib.parse.urlparse(sys.argv[1]).hostname)" "$URL"` should print a host.

Example fix

// before
HOST=""
lark-cli download url "https://$HOST/file.pdf"
// after
: "${HOST:?HOST must be set}"
lark-cli download url "https://$HOST/file.pdf"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(rawURL)
if err != nil || strings.TrimSpace(u.Hostname()) == "" {
    return fmt.Errorf("URL must include a host")
}

Try / catch

if err := validate.ValidateDownloadSourceURL(ctx, raw); err != nil {
    if strings.Contains(err.Error(), "URL host is required") {
        return fmt.Errorf("URL is missing its host; include the full domain: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: resolveDownloadHost receives rawHost that is empty after TrimSpace/ToLower — i.e. the parsed URL had no host, e.g. "https://" alone, or a URL like "https:///path".

Common situations: Truncated URLs where the domain was cut off during copy-paste, template variables that failed to expand ("https://$HOST/file" with HOST unset), or malformed links from documents.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/7583134b7eede497. Report an issue: GitHub.