tailscale/tailscale · warning
no address for node %v (v4-for-icmp)
Error message
no address for node %v (v4-for-icmp)
What it means
For ICMP latency probing, netcheck needs an IPv4 address for the DERP node (nodeAddrPort with probeIPv4). If the node's IPv4 field is empty or unparseable and no substitute address can be derived, the ICMP measurement for that region fails with the node name included.
Source
Thrown at net/netcheck/netcheck.go:1283
return nil
}
func (c *Client) measureICMPLatency(ctx context.Context, reg *tailcfg.DERPRegion, p *ping.Pinger) (_ time.Duration, ok bool, err error) {
if len(reg.Nodes) == 0 {
return 0, false, fmt.Errorf("no nodes for region %d (%v)", reg.RegionID, reg.RegionCode)
}
// Try pinging the first node in the region
node := reg.Nodes[0]
if node.STUNPort < 0 {
// If STUN is disabled on a node, interpret that as meaning don't measure latency.
return 0, false, nil
}
const unusedPort = 0
stunAddrPort, ok := c.nodeAddrPort(ctx, node, unusedPort, probeIPv4)
if !ok {
return 0, false, fmt.Errorf("no address for node %v (v4-for-icmp)", node.Name)
}
ip := stunAddrPort.Addr()
addr := &net.IPAddr{
IP: net.IP(ip.AsSlice()),
Zone: ip.Zone(),
}
// Use the unique node.Name field as the packet data to reduce the
// likelihood that we get a mismatched echo response.
d, err := p.Send(ctx, addr, []byte(node.Name))
if err != nil {
if errors.Is(err, syscall.EPERM) {
return 0, false, nil
}
return 0, false, err
}
return d, true, nil
}View on GitHub (pinned to 5201273aec)
Solutions
- Give every DERP node a valid IPv4 address in the map
- Or disable ICMP latency probing in the netcheck client configuration
- If IPv6-only DERP is intentional, treat this as per-region noise and rely on STUN/HTTPS latencies instead
Defensive patterns
Strategy: validation
Validate before calling
for _, reg := range dm.Regions {
for _, n := range reg.Nodes {
if _, err := netip.ParseAddr(n.IPv4); err != nil {
log.Printf("node %s lacks valid IPv4; ICMP latency will be skipped", n.Name)
}
}
} Type guard
func nodeHasIPv4(n *tailcfg.DERPNode) bool {
ip, err := netip.ParseAddr(n.IPv4)
return err == nil && ip.Is4()
} Try / catch
dur, ok, err := c.measureICMPLatency(ctx, reg, pinger)
if err != nil && strings.Contains(err.Error(), "no address for node") {
// per-node map gap: log and fall back to other latency probes
log.Printf("icmp latency unavailable: %v", err)
err = nil
} Prevention
- Always publish an IPv4 for every DERP node in custom maps
- Parse and lint node IPv4/IPv6 fields when loading a DERP map
- Configure netcheck expectations: ICMP probing is best-effort, not guaranteed
When it happens
Trigger: A DERP map node with only an IPv6 address, a typo'd IPv4 (e.g. '1.2.3.256'), or an empty IPv4 field while ICMP latency measurement is enabled.
Common situations: Hand-crafted DERP maps (headscale) that omit IPv4; IPv6-only DERP deployments; typos in node address fields.
Related errors
- both IPv4 and IPv6 are explicitly disabled for node
- no unexpected RemoteAddr %#v
- unexpected status code: %d (%s)
- no nodes for region %d (%v)
- DERP region not available
AI-assisted analysis of tailscale/tailscale@5201273aec (2026-08-18).
Data as JSON: /api/errors/eb249fe7f8e0c70d.
Report an issue: GitHub.