cloudflare/cloudflared · error

failed to send/receive ICMPv4 echo

Error message

failed to send/receive ICMPv4 echo

What it means

icmpEchoRoundtrip wraps failures from the ICMPv4 Windows API (IcmpSendEcho) with 'failed to send/receive ICMPv4 echo'. Any non-success from the Win32 roundtrip — API error, unreachable host, blocked ICMP — is surfaced through this message.

Solutions

  1. Confirm the destination replies to ICMP with the OS `ping` command.
  2. Check firewall/NAT rules that drop outbound ICMP echo requests.
  3. Verify the destination IP is correct and reachable on the current network.
  4. Inspect the inner error/status from IcmpSendEcho for the specific Win32 failure code.
Defensive patterns

Strategy: retry

Validate before calling

// Before probing, verify the destination is a reachable IPv4 address
ip := net.ParseIP(dstIP)
if ip == nil || ip.To4() == nil {
	// reject before calling the ICMP proxy
}

Try / catch

// Go: retry transient ICMP failures with a deadline
var resp *echoResp
var err error
for i := 0; i < 3 && ctx.Err() == nil; i++ {
	resp, err = proxy.Request(ctx, dst, echo)
	if err == nil {
		break
	}
	time.Sleep(500 * time.Millisecond)
}

Prevention

When it happens

Trigger: Request() on an ICMPv4 proxy where icmpSendEcho returns 0 replies: destination unreachable, IcmpCreateFile/IcmpSendEcho parameter failure, or the echo request timed out.

Common situations: Pinging hosts behind firewalls that drop ICMP, pinging non-existent addresses, running inside containers/NATs that block ICMP, or Windows privilege issues for raw ICMP sockets.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/4472da2451d9d7bb. Report an issue: GitHub.

Appendix: source

Thrown at ingress/icmp_windows.go:348

func (ip *icmpProxy) icmpEchoRoundtrip(dst netip.Addr, echo *icmp.Echo) (echoResp, error) {
	if dst.Is6() {
		if ip.srcSocketAddr == nil {
			return nil, fmt.Errorf("cannot send ICMPv6 using ICMPv4 proxy")
		}
		resp, err := ip.icmp6SendEcho(dst, echo)
		if err != nil {

			return nil, errors.Wrap(err, "failed to send/receive ICMPv6 echo")
		}
		return resp, nil
	}
	if ip.srcSocketAddr != nil {
		return nil, fmt.Errorf("cannot send ICMPv4 using ICMPv6 proxy")
	}
	resp, err := ip.icmpSendEcho(dst, echo)
	if err != nil {
		return nil, errors.Wrap(err, "failed to send/receive ICMPv4 echo")
	}
	return resp, nil
}

/*
Wrapper to call https://docs.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho
Parameters:
- IcmpHandle: Handle created by IcmpCreateFile
- DestinationAddress: IPv4 in the form of https://docs.microsoft.com/en-us/windows/win32/api/inaddr/ns-inaddr-in_addr#syntax
- RequestData: A pointer to echo data
- RequestSize: Number of bytes in buffer pointed by echo data
- RequestOptions: IP header options
- ReplyBuffer: A pointer to the buffer for echoReply, options and data
- ReplySize: Number of bytes allocated for ReplyBuffer
- Timeout: Timeout in milliseconds to wait for a reply
Returns:
- the number of replies in uint32 https://docs.microsoft.com/en-us/windows/win32/api/icmpapi/nf-icmpapi-icmpsendecho#return-value
To retain the reference allocated objects, conversion from pointer to uintptr must happen as arguments to the

View on GitHub (pinned to 2253eeeb25)