router-for-me/CLIProxyAPI · error

configure WebRTC UDP port range: %w

Error message

configure WebRTC UDP port range: %w

What it means

Thrown when SettingEngine.SetEphemeralUDPPortRange rejects the configured min/max port pair for the non-loopback Pion API. The pion API returns an error when min > max, when either port is outside 0-65535, or when the range includes privileged/invalid values. It comes from the codex-live-media-relay UDP port range config (UDPPortMin/UDPPortMax), only applied when not loopback-only and UDPPortMin != 0.

Source

Thrown at internal/client/codex/live/media.go:226

}

func newPionAPIWithOptions(relayConfig config.CodexLiveMediaRelayConfig, filterPrivateRemoteIPs, loopbackOnly bool) (*webrtc.API, error) {
	mediaEngine := &webrtc.MediaEngine{}
	if errRegister := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
		RTPCodecCapability: opusCodec,
		PayloadType:        111,
	}, webrtc.RTPCodecTypeAudio); errRegister != nil {
		return nil, fmt.Errorf("register Opus codec: %w", errRegister)
	}
	interceptorRegistry := &interceptor.Registry{}
	if errRegister := webrtc.RegisterDefaultInterceptors(mediaEngine, interceptorRegistry); errRegister != nil {
		return nil, fmt.Errorf("register WebRTC interceptors: %w", errRegister)
	}
	settingEngine := webrtc.SettingEngine{}
	if !loopbackOnly {
		if relayConfig.UDPPortMin != 0 {
			if errPorts := settingEngine.SetEphemeralUDPPortRange(relayConfig.UDPPortMin, relayConfig.UDPPortMax); errPorts != nil {
				return nil, fmt.Errorf("configure WebRTC UDP port range: %w", errPorts)
			}
		}
		if publicIP := strings.TrimSpace(relayConfig.PublicIP); publicIP != "" {
			settingEngine.SetNAT1To1IPs([]string{publicIP}, webrtc.ICECandidateTypeHost)
		}
	}
	if filterPrivateRemoteIPs {
		settingEngine.SetRemoteIPFilter(isPublicRemoteIP)
	}
	if loopbackOnly {
		settingEngine.SetNetworkTypes([]webrtc.NetworkType{
			webrtc.NetworkTypeUDP4,
			webrtc.NetworkTypeUDP6,
			webrtc.NetworkTypeTCP4,
			webrtc.NetworkTypeTCP6,
		})
		settingEngine.SetIncludeLoopbackCandidate(true)
		settingEngine.SetIPFilter(func(ip net.IP) bool {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Fix config so 0 < UDPPortMin <= UDPPortMax <= 65535 (e.g. min 50000, max 51000)
  2. Leave both unset (0) if you do not need a pinned UDP range — the code skips SetEphemeralUDPPortRange entirely
  3. Check config.CodexLiveMediaRelayConfig.Validate() if adding range validation so this fails at config load, not at relay construction

Example fix

# before (config.yaml)
codex-live-media-relay:
  udp-port-min: 61000
  udp-port-max: 50000

# after
codex-live-media-relay:
  udp-port-min: 50000
  udp-port-max: 61000
Defensive patterns

Strategy: validation

Validate before calling

if relayConfig.UDPPortMin != 0 {
	if relayConfig.UDPPortMin < 1 || relayConfig.UDPPortMax < relayConfig.UDPPortMin || relayConfig.UDPPortMax > 65535 {
		return fmt.Errorf("invalid UDP port range %d-%d", relayConfig.UDPPortMin, relayConfig.UDPPortMax)
	}
}

Prevention

When it happens

Trigger: Configuring relayConfig.UDPPortMin > relayConfig.UDPPortMax, setting a port above 65535 or negative, or setting only UDPPortMin while UDPPortMax stays 0 (min>max).

Common situations: YAML config typos in the media relay port range, swapping min and max keys, copying a range like 50000-40000, or setting UDPPortMin without UDPPortMax.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/c0c6201bb9f3d033. Report an issue: GitHub.