tsenart/vegeta · error

host %s is not an IP address

Error message

host %s is not an IP address

What it means

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.

Source

Thrown at internal/resolver/resolver.go:62

			addr += ":53"
		}

		// validate addr is a valid host:port
		host, portstr, err := net.SplitHostPort(addr)
		if err != nil {
			return nil, err
		}

		// validate valid port.
		_, err = strconv.ParseUint(portstr, 10, 16)
		if err != nil {
			return nil, err
		}

		// make sure host is an ip.
		ip := net.ParseIP(host)
		if ip == nil {
			return nil, fmt.Errorf("host %s is not an IP address", host)
		}

		normal[i] = addr
	}
	return normal, nil
}

// ignore the third parameter, as this represents the dns server address that
// we are overriding.
func (r *resolver) dial(ctx context.Context, network, _ string) (net.Conn, error) {
	return r.dialer.DialContext(ctx, network, r.address())
}

func (r *resolver) address() string {
	return r.addrs[atomic.AddUint64(&r.idx, 1)%uint64(len(r.addrs))]
}

View on GitHub (pinned to cf58112690)

Solutions

  1. Replace hostnames with IP literals, e.g. 93.184.216.34:80 instead of example.com:80.
  2. Resolve the hostname yourself (dig/nslookup or net.LookupHost) and pass the resulting IP.
  3. If you need hostname behavior, use the default resolver path instead of the IP-based one.
  4. Check each entry in the address map before constructing the resolver.

Example fix

// before
-connect-to=example.com:80:127.0.0.1:8080  # IP-requiring resolver path
// after
-connect-to=93.184.216.34:80:127.0.0.1:8080
Defensive patterns

Strategy: validation

Validate before calling

func allIPs(addrs []string) bool {
	for _, addr := range addrs {
		host, _, err := net.SplitHostPort(addr)
		if err != nil || net.ParseIP(host) == nil {
			return false
		}
	}
	return true
}

Prevention

When it happens

Trigger: 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.

Common situations: Assuming -connect-to accepts DNS names; config files with domain names; confusing the resolver's IP-only requirement with normal client DNS behavior.

Related errors


AI-assisted analysis of tsenart/vegeta@cf58112690 (2026-08-31). Data as JSON: /api/errors/63712e029b1c88e1. Report an issue: GitHub.