fatedier/frp · error
wait detect message timeout
Error message
wait detect message timeout
What it means
MakeHole listened on multiple UDP sockets concurrently and none of them received a valid detect message before the overall timeout (from DetectBehavior.ReadTimeoutMs, default 5s). The time.After(timeout) branch fired, meaning the hole-punch packet exchange produced no successful candidate connection across all sockets.
Source
Thrown at pkg/nathole/nathole.go:284
go func(lConn *net.UDPConn) {
addr, err := waitDetectMessage(ctx, lConn, m.Sid, key, timeout, m.DetectBehavior.Role)
if err != nil {
lConn.Close()
return
}
select {
case resultCh <- result{lConn: lConn, raddr: addr}:
default:
lConn.Close()
}
}(conn)
}
select {
case result := <-resultCh:
return result.lConn, result.raddr, nil
case <-time.After(timeout):
return nil, nil, fmt.Errorf("wait detect message timeout")
case <-ctx.Done():
return nil, nil, fmt.Errorf("wait detect message canceled")
}
}
func waitDetectMessage(
ctx context.Context, conn *net.UDPConn, sid string, key []byte,
timeout time.Duration, role string,
) (*net.UDPAddr, error) {
xl := xlog.FromContextSafe(ctx)
for {
buf := pool.GetBuf(1024)
_ = conn.SetReadDeadline(time.Now().Add(timeout))
n, raddr, err := conn.ReadFromUDP(buf)
_ = conn.SetReadDeadline(time.Time{})
if err != nil {
pool.PutBuf(buf)
return nil, errView on GitHub (pinned to 6c8a8d0a97)
Solutions
- Retry the P2P visit — multi-socket punching succeeds when the NAT mapping happens to align
- Confirm auth tokens match so detect messages decrypt on arrival
- If failures are consistent, disable P2P expectations for this pair and let traffic relay through frps
- Server operators: tune nathole DetectBehavior (more ports, longer ReadTimeoutMs) to widen the punch window
Defensive patterns
Strategy: retry
Try / catch
conn, addr, err := nathole.MakeHole(ctx, l, resp, key)
if errors.Is(err, errDetectTimeout) || strings.Contains(err.Error(), "wait detect message timeout") {
return relayFallback() // punch window exhausted across all sockets
} Prevention
- Retry P2P visits — multi-socket punching has a per-attempt success probability
- Classify consistent timeouts as symmetric-NAT topology and stop retrying, use relay
- Server operators: widen DetectBehavior ports/timeouts to raise punch success rate
When it happens
Trigger: MakeHole with len(listenConns) > 1 and no goroutine delivers a result to resultCh within the timeout — every waitDetectMessage on every socket missed the peer's detect packet.
Common situations: Symmetric NAT on the peer side maps each outbound socket to a different port so none of the guessed candidates is correct; aggressive UDP firewalls; timeouts too short for high-latency links.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- wait detect message error: %v
- open tunnel timeout
- dial quic error: %v
- natHoleRespMsg get error info: %s
- natHoleRespMsg get empty candidate addresses
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/b331c62187e33ea2.
Report an issue: GitHub.