{"record":{"id":"fe8a37917ed473b9","repo":"googleapis/mcp-toolbox","slug":"failed-to-resolve-redirect-host-s-w","errorCode":null,"errorMessage":"failed to resolve redirect host %s: %w","messagePattern":"failed to resolve redirect host (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/http/http.go","lineNumber":369,"sourceCode":"\tclient := &http.Client{\n\t\tTimeout:   duration,\n\t\tTransport: tr,\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\tif len(via) >= 10 {\n\t\t\t\treturn fmt.Errorf(\"stopped after 10 redirects\")\n\t\t\t}\n\n\t\t\thostname := req.URL.Hostname()\n\t\t\tif ip := net.ParseIP(hostname); ip != nil {\n\t\t\t\tif guard.IsIPBlocked(ip) {\n\t\t\t\t\treturn fmt.Errorf(\"redirect to blocked IP %s denied\", ip)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\taddrs, err := resolver.LookupHost(req.Context(), hostname)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to resolve redirect host %s: %w\", hostname, err)\n\t\t\t}\n\n\t\t\tfor _, addr := range addrs {\n\t\t\t\tif ip := net.ParseIP(addr); ip != nil {\n\t\t\t\t\tif guard.IsIPBlocked(ip) {\n\t\t\t\t\t\treturn fmt.Errorf(\"redirect host %s resolves to blocked IP %s\", hostname, addr)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n\treturn client, nil\n}\n","sourceCodeStart":351,"sourceCodeEnd":385,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/http/http.go#L351-L385","documentation":"For redirects to hostname-based (non-literal-IP) URLs, the source performs a DNS lookup (resolver.LookupHost) so it can vet every resolved address against the SSRF guard before following. If DNS resolution itself fails, the redirect is refused and this wrapped error is returned. The original resolver error is included via %w.","triggerScenarios":"A redirect Location header whose hostname cannot be resolved by the configured DNS resolver: NXDOMAIN, no network/DNS server, or resolver timeout during CheckRedirect.","commonSituations":"Redirect to a stale/decommissioned domain; DNS outage or misconfigured resolver in the container (e.g. missing resolv.conf entries); typos in a redirect target set up server-side.","solutions":["Fix the server-side redirect so it points at a resolvable, valid hostname.","Check DNS connectivity from the host running the toolbox (nslookup/getent hosts <hostname>).","Verify the container's DNS configuration (/etc/resolv.conf) and that the hostname exists in the relevant DNS zone."],"exampleFix":"// server-side before: redirect to https://old.example.internal/... (NXDOMAIN)\n// after: redirect to a live host\nw.Header().Set(\"Location\", \"https://new.example.com/path\")","handlingStrategy":"validation","validationCode":"const host = new URL(redirectTarget).hostname;\nconst res = await require('dns').promises.lookup(host).catch(() => null);\nif (!res) console.warn(`hostname ${host} will fail DNS resolution on redirect; fix the redirect target`);","typeGuard":null,"tryCatchPattern":"try {\n  const result = await callHttpTool(url);\n} catch (err) {\n  if (String(err).startsWith('failed to resolve redirect host')) {\n    const host = err.match(/redirect host ([^:]+):/)?.[1];\n    console.error(`DNS failure for redirect host ${host}; check DNS config and the redirect target.`);\n  } else throw err;\n}","preventionTips":["Verify /etc/resolv.conf and DNS egress in containers running the toolbox.","Decommission redirect rules pointing at retired domains.","Resolve every redirect hostname with getent/nslookup during pre-deployment checks."],"tags":["dns","redirect","network"],"backgroundTag":"dns-resolution-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}