{"record":{"id":"bbde993e846bce76","repo":"MHSanaei/3x-ui","slug":"cannot-resolve-host-s-w","errorCode":null,"errorMessage":"cannot resolve host %s: %w","messagePattern":"cannot resolve host (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/web/service/url_safety.go","lineNumber":73,"sourceCode":"\t}\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\tif err := rejectPrivateHost(ctx, u.Hostname()); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn clean, nil\n}\n\nfunc rejectPrivateHost(ctx context.Context, hostname string) error {\n\tif ip := net.ParseIP(hostname); ip != nil {\n\t\tif isBlockedIP(ip) {\n\t\t\treturn fmt.Errorf(\"blocked private/internal address %s\", ip.String())\n\t\t}\n\t\treturn nil\n\t}\n\tips, err := net.DefaultResolver.LookupIPAddr(ctx, hostname)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot resolve host %s: %w\", hostname, err)\n\t}\n\tif len(ips) == 0 {\n\t\treturn fmt.Errorf(\"host %s has no IP addresses\", hostname)\n\t}\n\tfor _, ipAddr := range ips {\n\t\tif isBlockedIP(ipAddr.IP) {\n\t\t\treturn fmt.Errorf(\"host %s resolves to blocked private/internal address %s\", hostname, ipAddr.IP.String())\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc isBlockedIP(ip net.IP) bool {\n\treturn netsafe.IsBlockedIP(ip)\n}\n","sourceCodeStart":55,"sourceCodeEnd":89,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/url_safety.go#L55-L89","documentation":"rejectPrivateHost wraps the net.DefaultResolver.LookupIPAddr error when the URL's hostname is a name (not an IP literal) and DNS resolution fails within the 5-second context. Typical wrapped causes: NXDOMAIN (no such host), resolver unreachable/timeout, or SERVFAIL. Because this runs under a 5s context, slow resolvers surface as 'context deadline exceeded' here.","triggerScenarios":"Any SanitizePublicHTTPURL call whose hostname doesn't exist ('http://typo.example/'), whose DNS is broken on the panel host, or where resolution takes >5s (misconfigured resolv.conf, unreachable nameserver, DNSSEC failures).","commonSituations":"Typos in configured hostnames; panel host with no working /etc/resolv.conf (common in minimal containers); DNSSEC/CAA oddities; loss of egress UDP/53 in firewalled environments.","solutions":["Verify the name resolves on the panel host itself: 'nslookup <host>' / 'getent hosts <host>'; fix resolv.conf or the firewall if not.","Correct the hostname typo — the wrapped error usually contains 'no such host' for NXDOMAIN.","If resolution legitimately takes long (chained resolvers), fix the resolver chain rather than raising the 5s context: this path guards live outbound requests and must stay fast.","Retry once — NXDOMAIN for a just-created DNS record can be negative-cache lag (up to the TTL)."],"exampleFix":"// before\nhost := \"healtch.example.com\" // typo\nclean, err := SanitizePublicHTTPURL(\"https://\" + host + \"/ping\")\n\n// after\nhost := \"health.example.com\"\nclean, err := SanitizePublicHTTPURL(\"https://\" + host + \"/ping\")","handlingStrategy":"retry","validationCode":"// Resolve the hostname once up front with a tight timeout; fail fast with a clear message\nctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\ndefer cancel()\nif _, err := net.DefaultResolver.LookupHost(ctx, hostname); err != nil {\n    return fmt.Errorf(\"hostname %q does not resolve from this host: %w\", hostname, err)\n}","typeGuard":"null","tryCatchPattern":"if err := ctxErr(ctx); err != nil { /* deadline: check resolver health, then single retry */ }\nif strings.Contains(err.Error(), \"no such host\") { /* typo: fix name, no retry */ }","preventionTips":["Smoke-test configured hostnames with getent/dig when saving settings.","Keep the panel host's resolv.conf pointed at fast, reachable resolvers."],"tags":["dns","network","ssrf","url"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}