fatedier/frp · error

discover error: %v

Error message

discover error: %v

What it means

Returned by nathole.Prepare (pkg/nathole/nathole.go) when Discover(stunServers, "") fails outright before any addresses are gathered. The wrapped error comes from the discovery layer — typically every STUN server timing out ('wait response from stun server timeout') or responding without a mapped address ('no external address found').

Source

Thrown at pkg/nathole/nathole.go:122

	}
	mm, ok := m.(*msg.NatHoleResp)
	if !ok {
		return fmt.Errorf("get natHoleRespMsg error: invalid message type")
	}
	natHoleRespMsg = mm

	if natHoleRespMsg.Error != "" {
		return fmt.Errorf("%s", natHoleRespMsg.Error)
	}
	return nil
}

// Prepare is used to do some preparation work before penetration.
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)

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Check the wrapped error to distinguish timeout (blocked/dead server) from no-mapped-address (bad server)
  2. Verify outbound UDP to the STUN servers works from this host
  3. Configure multiple valid STUN servers on frps
  4. If UDP is blocked, hole punching is impossible — use stcp/tcp relay instead of xtcp
Defensive patterns

Strategy: fallback

Try / catch

res, err := nathole.Prepare(servers, opts)
if err != nil {
    if strings.Contains(err.Error(), "discover error:") && !strings.Contains(err.Error(), "not enough addresses") {
        // all STUN failed: check UDP egress; if blocked, use stcp/tcp instead of xtcp
    }
}

Prevention

When it happens

Trigger: nathole.Prepare(stunServers, opts) where all STUN servers fail: unreachable/dead servers, UDP fully blocked by the local firewall, DNS failure resolving server hostnames.

Common situations: Running xtcp on hosts with outbound UDP denied; empty or stale natHoleSTUNServer config; captive portals or VPNs swallowing UDP; containers with restricted networking.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/725a60b2e1b90366. Report an issue: GitHub.