{"record":{"id":"63712e029b1c88e1","repo":"tsenart/vegeta","slug":"host-s-is-not-an-ip-address","errorCode":null,"errorMessage":"host %s is not an IP address","messagePattern":"host (.+?) is not an IP address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/resolver/resolver.go","lineNumber":62,"sourceCode":"\t\t\taddr += \":53\"\n\t\t}\n\n\t\t// validate addr is a valid host:port\n\t\thost, portstr, err := net.SplitHostPort(addr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// validate valid port.\n\t\t_, err = strconv.ParseUint(portstr, 10, 16)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// make sure host is an ip.\n\t\tip := net.ParseIP(host)\n\t\tif ip == nil {\n\t\t\treturn nil, fmt.Errorf(\"host %s is not an IP address\", host)\n\t\t}\n\n\t\tnormal[i] = addr\n\t}\n\treturn normal, nil\n}\n\n// ignore the third parameter, as this represents the dns server address that\n// we are overriding.\nfunc (r *resolver) dial(ctx context.Context, network, _ string) (net.Conn, error) {\n\treturn r.dialer.DialContext(ctx, network, r.address())\n}\n\nfunc (r *resolver) address() string {\n\treturn r.addrs[atomic.AddUint64(&r.idx, 1)%uint64(len(r.addrs))]\n}\n","sourceCodeStart":44,"sourceCodeEnd":79,"githubUrl":"https://github.com/tsenart/vegeta/blob/cf5811269046c672a604b1eb352204d30f16ae4a/internal/resolver/resolver.go#L44-L79","documentation":"vegeta's internal resolver, used with -connect-to / custom DNS handling, requires each address host to be a literal IP because it bypasses normal name resolution. normalizeAddrs parses each host with net.ParseIP and fails the whole resolution if any host is a hostname rather than an IP.","triggerScenarios":"Calling NewResolver (or the anonymous function it calls) with address lists containing hostnames like \"example.com:80\" instead of IP literals; commonly reached by passing hostnames in -connect-to mappings.","commonSituations":"Assuming -connect-to accepts DNS names; config files with domain names; confusing the resolver's IP-only requirement with normal client DNS behavior.","solutions":["Replace hostnames with IP literals, e.g. 93.184.216.34:80 instead of example.com:80.","Resolve the hostname yourself (dig/nslookup or net.LookupHost) and pass the resulting IP.","If you need hostname behavior, use the default resolver path instead of the IP-based one.","Check each entry in the address map before constructing the resolver."],"exampleFix":"// before\n-connect-to=example.com:80:127.0.0.1:8080  # IP-requiring resolver path\n// after\n-connect-to=93.184.216.34:80:127.0.0.1:8080","handlingStrategy":"validation","validationCode":"func allIPs(addrs []string) bool {\n\tfor _, addr := range addrs {\n\t\thost, _, err := net.SplitHostPort(addr)\n\t\tif err != nil || net.ParseIP(host) == nil {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use IP literals, not hostnames, wherever the resolver requires IPs.","Pre-resolve DNS names with net.LookupHost before configuring.","Document that -connect-to paths may bypass DNS.","Validate each host with net.ParseIP before constructing the resolver."],"tags":["network","dns","ip-validation"],"backgroundTag":"invalid-ip-address","analyzedSha":"cf5811269046c672a604b1eb352204d30f16ae4a","analyzedAt":"2026-08-31T11:04:20.464Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}