router-for-me/CLIProxyAPI · error

create downstream PeerConnection: %w

Error message

create downstream PeerConnection: %w

What it means

Thrown when r.downstreamAPI.NewPeerConnection(r.configuration) fails while creating the peer connection facing the local client. Pion returns errors for invalid ICE server URLs, bad STUN/TURN configuration, or an expired/closed API object. The limiter slot acquired just before is released via releaseSlot(). This is the first PeerConnection of the two the relay creates per session.

Source

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

		return nil, "", fmt.Errorf("configure Codex live remote TCP proxy: %w", errProxy)
	}
	proxied := proxyMode == proxyutil.ModeProxy
	var proxyDialer proxy.ContextDialer
	if proxied {
		contextDialer, ok := builtProxyDialer.(proxy.ContextDialer)
		if !ok {
			return nil, "", errors.New("Codex live remote TCP proxy does not support cancellation")
		}
		proxyDialer = contextDialer
	}
	if !r.limiter.acquire() {
		return nil, "", errors.New("Codex live media relay capacity exhausted")
	}
	releaseSlot := r.limiter.release
	downstream, errDownstream := r.downstreamAPI.NewPeerConnection(r.configuration)
	if errDownstream != nil {
		releaseSlot()
		return nil, "", fmt.Errorf("create downstream PeerConnection: %w", errDownstream)
	}
	upstreamAPI := r.upstreamAPI
	upstreamConfiguration := r.configuration
	if proxied {
		upstreamAPI = r.proxyUpstreamAPI
		upstreamConfiguration.ICEServers = nil
	}
	upstream, errUpstream := upstreamAPI.NewPeerConnection(upstreamConfiguration)
	if errUpstream != nil {
		releaseSlot()
		if errClose := downstream.Close(); errClose != nil {
			log.WithError(errClose).Debug("codex live media: close downstream PeerConnection after setup error")
		}
		return nil, "", fmt.Errorf("create upstream PeerConnection: %w", errUpstream)
	}

	session := &pionMediaSession{
		downstream:     downstream,

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Validate every ICE server URL in codex-live-media-relay config (scheme stun/turn/turns, resolvable host, valid port)
  2. Retry the call once — ICE agent setup can fail transiently under fd/memory pressure
  3. Check host resource limits (ulimit -n) if failures cluster under load
  4. Verify credentials for TURN servers are current

Example fix

# before
codex-live-media-relay:
  ice-servers:
    - urls: ["turn turn.example.com"]

# after
codex-live-media-relay:
  ice-servers:
    - urls: ["turn:turn.example.com:3478?transport=udp"]
      username: user
      credential: pass
Defensive patterns

Strategy: retry

Validate before calling

for _, server := range relayConfig.ICEServers {
	for _, raw := range server.URLs {
		u, err := url.Parse(strings.TrimSpace(raw))
		if err != nil || (u.Scheme != "stun" && u.Scheme != "turn" && u.Scheme != "turns") {
			return fmt.Errorf("invalid ICE server URL %q", raw)
		}
	}
}

Try / catch

var downstream *webrtc.PeerConnection
var errDownstream error
for attempt := 0; attempt < 2; attempt++ {
	downstream, errDownstream = api.NewPeerConnection(cfg)
	if errDownstream == nil {
		break
	}
}

Prevention

When it happens

Trigger: An ICE server entry in relayConfig.ICEServers with a malformed URL (wrong scheme, bad port), a TURN credential type mismatch, or resource exhaustion (socket/ICE agent creation failure) at session start.

Common situations: Bad stun:/turn: URL in the media relay config, TURN server password errors surfaced at PC creation, or transient fd exhaustion on a loaded host.

Related errors


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