XTLS/Xray-core · error

invalid destination IP address:

Error message

invalid destination IP address: 

What it means

On macOS, FindProcess optionally parses destIP (when both destIP is non-empty and destPort is non-zero) with netip.ParseAddr, and it failed. Like error 178, the destination must be a bare IP literal — hostnames, empty ports with non-empty IPs are handled, but malformed IP text aborts the lookup.

Source

Thrown at common/net/find_process_darwin.go:75

	if !isLocal {
		return 0, "", "", ErrNotLocal
	}
	if network != "tcp" && network != "udp" {
		panic("Unsupported network type for process lookup.")
	}

	srcAddr, err := netip.ParseAddr(srcIP)
	if err != nil {
		return 0, "", "", errors.New("invalid source IP address: ", srcIP)
	}
	srcAddr = srcAddr.Unmap()

	var dstAddr netip.Addr
	hasDstAddr := false
	if destIP != "" && destPort != 0 {
		dstAddr, err = netip.ParseAddr(destIP)
		if err != nil {
			return 0, "", "", errors.New("invalid destination IP address: ", destIP)
		}
		dstAddr = dstAddr.Unmap()
		hasDstAddr = true
	}

	processes, err := unix.SysctlKinfoProcSlice("kern.proc.all")
	if err != nil {
		return 0, "", "", errors.New("failed to list processes").Base(err)
	}

	var bestPID int32
	bestLevel := darwinSocketNoMatch
	ambiguousBest := false

	for _, process := range processes {
		pid := process.Proc.P_pid
		if pid <= 0 {
			continue

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Resolve hostnames to IPs before calling FindProcess, or omit both destIP and destPort (pass "" and 0) to skip exact-match narrowing.
  2. Validate with net.ParseIP(destIP) != nil at the call site and degrade gracefully (fall back to lookup without destination filter).
  3. Ensure IPv6 addresses are passed without surrounding brackets.
  4. Log the offending destIP value to catch formatting bugs quickly.

Example fix

// before
pid, name, path, err := net.FindProcess("tcp", srcIP, srcPort, "example.com", 443)
// after: resolve first, or omit destination narrowing
var dstIPStr string
if ip := net.ParseIP(dstHost); ip != nil {
    dstIPStr = ip.String()
}
pid, name, path, err := net.FindProcess("tcp", srcIP, srcPort, dstIPStr, dstPort)
Defensive patterns

Strategy: validation

Validate before calling

if destIP != "" && destPort != 0 {
    if _, err := netip.ParseAddr(destIP); err != nil {
        return errors.New("destIP is not an IP literal; pass empty dest to skip narrowing")
    }
}

Type guard

func isParseableDest(ip string, port uint16) bool {
    if ip == "" || port == 0 { return true } // optional: absent is fine
    _, err := netip.ParseAddr(ip)
    return err == nil
}

Try / catch

pid, name, path, err := net.FindProcess(network, srcIP, srcPort, destIP, destPort)
if err != nil && strings.Contains(err.Error(), "invalid destination IP address") {
    // retry once without destination narrowing (destIP="", destPort=0)
    pid, name, path, err = net.FindProcess(network, srcIP, srcPort, "", 0)
}

Prevention

When it happens

Trigger: destIP is a hostname (e.g. 'example.com'), contains brackets/zone, or is otherwise unparsable while destPort != 0.

Common situations: Callers resolving the destination to a domain name instead of an IP before invoking process lookup, or tests passing placeholder destination strings.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/6ab9dcade34fd7ea. Report an issue: GitHub.