router-for-me/CLIProxyAPI · error
create upstream PeerConnection: %w
Error message
create upstream PeerConnection: %w
What it means
Thrown when the second PeerConnection (toward OpenAI's upstream) cannot be created — either the plain upstream API or, when a proxy is configured, proxyUpstreamAPI with ICEServers stripped. The downstream PeerConnection and the limiter slot are cleaned up before returning. Same pion failure classes as downstream creation, plus anything specific to the proxy-routed SettingEngine.
Source
Thrown at internal/client/codex/live/media.go:301
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,
upstream: upstream,
done: make(chan struct{}),
mediaSessionID: uuid.NewString(),
releaseSlot: releaseSlot,
proxyDialer: proxyDialer,
proxyScheme: proxyScheme(route.proxyURL),
credential: strings.TrimSpace(route.credential),
authIndex: strings.TrimSpace(route.authIndex),
}
session.bridge = newDataChannelBridge(session.done, func(err error) {
session.fail("data_channel_failed", err)
})
session.installStateHandlers()
log.WithFields(session.logFields("session")).Info("codex live WebRTC media session created")View on GitHub (pinned to 78f0c4079e)
Solutions
- Apply the same ICE server URL/credential validation as for the downstream leg
- If using a proxy route, check the proxy itself is reachable and correctly configured (error 322 precedes this)
- Retry once for transient ICE-agent creation failures
- Raise max-sessions only after ruling out resource exhaustion (the limiter correctly frees the slot here)
Defensive patterns
Strategy: retry
Try / catch
if _, _, err := relay.NewSession(ctx, offer, route); err != nil {
if strings.Contains(err.Error(), "create upstream PeerConnection") {
// session state was cleaned up; safe to retry once
time.Sleep(100 * time.Millisecond)
_, _, err = relay.NewSession(ctx, offer, route)
}
} Prevention
- Same ICE/resource hygiene as the downstream leg
- Rely on NewSession's built-in cleanup (downstream Close + limiter release) rather than partial retries
- Alert when both legs fail together — points at host-level resource issues
When it happens
Trigger: Same as 323 but on the upstream leg; with proxied=true, failure is tied to the loopback-only proxy API configuration rather than ICE servers (they are nil'd for the proxy path).
Common situations: Malformed STUN/TURN URLs (non-proxied path), ICE agent creation failure on the loopback-only proxy API, or resource exhaustion while two PCs are being created back to back.
Related errors
- create downstream PeerConnection: %w
- upstream WebRTC offer is empty
- downstream WebRTC answer is empty
- SDP contains incomplete ICE credentials
- SDP contains inconsistent bundled ICE credentials
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/e1a1c2e16b8aa8d5.
Report an issue: GitHub.