fatedier/frp · error
resolve local udp addr error: %v
Error message
resolve local udp addr error: %v
What it means
Returned by nathole.Prepare (pkg/nathole/nathole.go) when net.ResolveUDPAddr("udp4", localAddr.String()) fails. Prepare re-resolves the local address discovered during STUN binding as an explicit udp4 address before listening on it; failure means the discovered local address string cannot be parsed as an IPv4 UDP endpoint.
Source
Thrown at pkg/nathole/nathole.go:136
func Prepare(stunServers []string, opts PrepareOptions) (*PrepareResult, error) {
// discover for Nat type
addrs, localAddr, err := Discover(stunServers, "")
if err != nil {
return nil, fmt.Errorf("discover error: %v", err)
}
if len(addrs) < 2 {
return nil, fmt.Errorf("discover error: not enough addresses")
}
localIPs, _ := ListLocalIPsForNatHole(10)
natFeature, err := ClassifyNATFeature(addrs, localIPs)
if err != nil {
return nil, fmt.Errorf("classify nat feature error: %v", err)
}
laddr, err := net.ResolveUDPAddr("udp4", localAddr.String())
if err != nil {
return nil, fmt.Errorf("resolve local udp addr error: %v", err)
}
listenConn, err := net.ListenUDP("udp4", laddr)
if err != nil {
return nil, fmt.Errorf("listen local udp addr error: %v", err)
}
// Apply NAT traversal options
var assistedAddrs []string
if !opts.DisableAssistedAddrs {
assistedAddrs = make([]string, 0, len(localIPs))
for _, ip := range localIPs {
assistedAddrs = append(assistedAddrs, net.JoinHostPort(ip, strconv.Itoa(laddr.Port)))
}
}
return &PrepareResult{
Addrs: addrs,
AssistedAddrs: assistedAddrs,
ListenConn: listenConn,View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Force IPv4 for STUN discovery — use IPv4 literals or hostnames that resolve A records for the STUN servers
- Disable IPv6 on the socket/host if the environment prefers v6 unexpectedly
- Check the wrapped error text; anything other than address-family mismatch is a genuine malformed address and worth reporting
Example fix
# before natHoleSTUNServer = ["stun.example.com:3478"] # may resolve to IPv6 # after natHoleSTUNServer = ["203.0.113.20:3478"] # IPv4 literal forces udp4 path
Defensive patterns
Strategy: validation
Validate before calling
if localAddr != nil && localAddr.IP.To4() == nil {
// discovery happened over IPv6; force IPv4 STUN endpoints before Prepare
} Try / catch
if err != nil && strings.Contains(err.Error(), "resolve local udp addr error") {
// switch STUN config to IPv4 literals/endpoints and retry Prepare
} Prevention
- Use IPv4 STUN server addresses for xtcp
- Check host DNS resolution prefers A records for STUN hostnames
- Disable IPv6 for the frpc socket if the environment is dual-stack
When it happens
Trigger: nathole.Prepare where localAddr (the local socket address from discovery) stringifies into something unresolvable as udp4 — e.g. an IPv6 local address on a dual-stack socket, since the network is hard-coded to "udp4" here.
Common situations: Host whose STUN exchange ran over IPv6 (STUN server resolved to an AAAA record) so the local endpoint is IPv6 while Prepare demands udp4; unusual local address formats from the OS.
Related errors
- wait response from stun server timeout
- no external address found
- get natHoleRespMsg error: %v
- discover error: %v
- listen local udp addr error: %v
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/7a54cc66fd679db7.
Report an issue: GitHub.