{"record":{"id":"6556d16c17e59e3b","repo":"larksuite/cli","slug":"failed-to-resolve-host","errorCode":null,"errorMessage":"failed to resolve host","messagePattern":"failed to resolve host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/validate/url.go","lineNumber":114,"sourceCode":"\thost := strings.TrimSpace(strings.ToLower(rawHost))\n\tif host == \"\" {\n\t\treturn nil, fmt.Errorf(\"URL host is required\")\n\t}\n\tif host == \"localhost\" || strings.HasSuffix(host, \".localhost\") {\n\t\treturn nil, fmt.Errorf(\"local/internal host is not allowed\")\n\t}\n\tif ip := net.ParseIP(host); ip != nil {\n\t\tif isRestrictedDownloadIP(ip) {\n\t\t\treturn nil, fmt.Errorf(\"local/internal host is not allowed\")\n\t\t}\n\t\treturn []net.IP{ip}, nil\n\t}\n\tif lookupIP == nil {\n\t\tlookupIP = net.DefaultResolver.LookupIP\n\t}\n\tips, err := lookupIP(ctx, \"ip\", host)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to resolve host\")\n\t}\n\tif len(ips) == 0 {\n\t\treturn nil, fmt.Errorf(\"failed to resolve host\")\n\t}\n\tfor _, ip := range ips {\n\t\tif isRestrictedDownloadIP(ip) {\n\t\t\treturn nil, fmt.Errorf(\"local/internal host is not allowed\")\n\t\t}\n\t}\n\treturn ips, nil\n}\n\n// NewDownloadHTTPClient clones base client and enforces download-safe redirect\n// and connection rules for untrusted URLs.\nfunc NewDownloadHTTPClient(base *http.Client, opts DownloadHTTPClientOptions) *http.Client {\n\tif base == nil {\n\t\tbase = &http.Client{}\n\t}","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/internal/validate/url.go#L96-L132","documentation":"DNS resolution of the download host failed: the lookupIP call (default net.DefaultResolver.LookupIP) returned an error, so resolveDownloadHost cannot verify the host is safe. The library deliberately discards the underlying DNS error and returns the opaque message \"failed to resolve host\" so callers get a uniform, non-leaking message. No IPs means no download and no SSRF risk can be assessed.","triggerScenarios":"ValidateDownloadSourceURL (or a proxied download RoundTrip) with a hostname the configured DNS resolver cannot resolve: NXDOMAIN, resolver timeout/cancellation via ctx, broken /etc/resolv.conf, no network, or a corporate VPN/DNS that refuses external lookups.","commonSituations":"Typo in the hostname; offline machine or flaky network; DNS server down or firewalled; inside a container with no DNS configured; VPN split-DNS hiding the domain; context cancelled mid-lookup; air-gapped CI runners.","solutions":["Check the hostname spelling and confirm the domain actually exists (dig/nslookup with the same resolver).","Verify DNS connectivity: test another domain, inspect /etc/resolv.conf, and fix resolver/VPN/firewall settings.","Ensure the Go context passed in is not already cancelled or too short for a DNS round trip.","Retry once connectivity is restored; transient resolver failures are common on flaky networks.","If resolution genuinely fails for the whole network, fetch the file from a different, resolvable source."],"exampleFix":"// before (host does not exist)\nerr := validate.ValidateDownloadSourceURL(ctx, \"https://download.exmaple.com/file.zip\")\n// after (typo fixed)\nerr := validate.ValidateDownloadSourceURL(ctx, \"https://download.example.com/file.zip\")","handlingStrategy":"retry","validationCode":"host := u.Hostname()\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\nif _, err := net.DefaultResolver.LookupIP(ctx, \"ip\", host); err != nil {\n    return fmt.Errorf(\"download host %q is not resolvable right now: %v\", host, err)\n}","typeGuard":null,"tryCatchPattern":"ips, err := validateDownload(ctx, url)\nif err != nil && strings.Contains(err.Error(), \"failed to resolve host\") {\n    // check network/DNS, then retry with backoff\n    time.Sleep(2 * time.Second)\n    ips, err = validateDownload(ctx, url)\n    if err != nil {\n        return fmt.Errorf(\"download source %q unreachable: check DNS/network: %w\", url, err)\n    }\n}","preventionTips":["Verify hostnames with dig/nslookup before adding them to config.","Use a resolver-backed context with a reasonable timeout; treat resolver errors as transient.","Check /etc/resolv.conf, VPN, and firewall DNS rules in CI/containers.","Surface the underlying DNS error in your own tooling by doing your own pre-check lookup."],"tags":["dns","network","resolution-failure"],"backgroundTag":"dns-resolution-failed","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}