fatedier/frp · error

no external address found

Error message

no external address found

What it means

Returned by discoverFromStunServer in pkg/nathole/discovery.go when a STUN binding response arrives but contains no MAPPED-ADDRESS attribute, so externalAddr stays empty. A STUN reply without a mapped address carries no information about the observer's public endpoint, so discovery from that server is useless and fails.

Source

Thrown at pkg/nathole/discovery.go:126

	}

	resp := &stunResponse{}
	if response.MappedAddr != nil {
		resp.externalAddr = response.MappedAddr.String()
	}
	if response.OtherAddr != nil {
		resp.otherAddr = response.OtherAddr.String()
	}
	return resp, nil
}

func (c *discoverConn) discoverFromStunServer(addr string) ([]string, error) {
	resp, err := c.doSTUNRequest(addr)
	if err != nil {
		return nil, err
	}
	if resp.externalAddr == "" {
		return nil, fmt.Errorf("no external address found")
	}

	externalAddrs := make([]string, 0, 2)
	externalAddrs = append(externalAddrs, resp.externalAddr)

	if resp.otherAddr == "" {
		return externalAddrs, nil
	}

	// find external address from changed address
	resp, err = c.doSTUNRequest(resp.otherAddr)
	if err != nil {
		return nil, err
	}
	if resp.externalAddr != "" {
		externalAddrs = append(externalAddrs, resp.externalAddr)
	}
	return externalAddrs, nil

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Replace the STUN server with a known-compliant one (standard RFC 5389/8489 servers)
  2. Verify the port — most STUN servers listen on 3478 UDP
  3. Confirm nothing on the path intercepts and answers the UDP traffic
  4. Use multiple STUN servers so one bad entry does not kill discovery

Example fix

# before
natHoleSTUNServer = ["203.0.113.10:3478"]  # answers, but never maps

# after
natHoleSTUNServer = ["stun.easyvoip.com:3478", "stun.l.google.com:19302"]
Defensive patterns

Strategy: fallback

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "no external address found") {
        // this server is not a healthy STUN endpoint: skip it and use the next configured server
    }
}

Prevention

When it happens

Trigger: discoverFromStunServer(addr) where the server responded but response.MappedAddr is nil. Causes: a misbehaving or non-compliant STUN server, a proxy/redirector answering UDP on that port with non-STUN data that happened to parse, or protocol-version mismatch in the STUN exchange.

Common situations: Pointing natHoleSTUNServer at a host that is not actually a STUN server; a STUN server that answers errors only; middleboxes (transparent proxies) replying to arbitrary UDP; a server that only speaks an incompatible STUN flavor.

Related errors


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