router-for-me/CLIProxyAPI · error
upstream WebRTC answer has no supported public TCP passive c
Error message
upstream WebRTC answer has no supported public TCP passive candidate on port 443
What it means
Thrown by prepareProxiedUpstreamAnswer when a TCP proxy dialer is configured and the upstream Codex WebRTC answer was parsed and filtered, but zero candidate lines survived. The proxy path only rewrites 'host/tcp/passive/RTP-component' candidates listening on port 443; if the upstream returned only UDP candidates, srflx/relay candidates, active TCP, or TCP on another port, plans ends up empty and the error is returned.
Source
Thrown at internal/client/codex/live/tcp_proxy.go:147
plan, keep, errCandidate := proxiedTCPCandidatePlan(attribute.Value)
if errCandidate != nil {
return "", nil, errCandidate
}
if !keep {
continue
}
if len(plans) >= maxProxiedTCPCandidates {
return "", nil, fmt.Errorf("upstream WebRTC answer exceeds the %d TCP candidate proxy limit", maxProxiedTCPCandidates)
}
plan.mediaIndex = mediaIndex
plan.attributeIndex = len(filtered)
filtered = append(filtered, attribute)
plans = append(plans, plan)
}
media.Attributes = filtered
}
if len(plans) == 0 {
return "", nil, errors.New("upstream WebRTC answer has no supported public TCP passive candidate on port 443")
}
expectedUser := remoteCredentials.ufrag + ":" + localCredentials.ufrag
tunnels := make([]*tcpCandidateTunnel, 0, len(plans))
closeTunnels := func() {
for _, tunnel := range tunnels {
if errClose := tunnel.Close(); errClose != nil {
log.WithError(errClose).Debug("codex live TCP proxy: close candidate tunnel after setup error")
}
}
}
for _, plan := range plans {
tunnel, errTunnel := newTCPCandidateTunnel(plan.target, dialer, expectedUser, remoteCredentials.password)
if errTunnel != nil {
closeTunnels()
return "", nil, errTunnel
}
tunnels = append(tunnels, tunnel)View on GitHub (pinned to 78f0c4079e)
Solutions
- Capture the raw upstream answer SDP (log it at debug level) and inspect the a=candidate lines for tcp passive port 443 entries
- If the upstream no longer offers TCP passive on 443, disable the TCP proxy dialer for this session so the relay uses direct connectivity
- Verify the proxy dialer configuration actually points at a proxy the upstream supports — the server may serve different candidate sets depending on how the signaling connection was established
- Report upstream candidate-set changes to the maintainers if the SDP genuinely lacks supported candidates
Defensive patterns
Strategy: fallback
Try / catch
sdp, tunnels, err := live.PrepareProxiedUpstreamAnswer(answer, offer, dialer)
if err != nil && strings.Contains(err.Error(), "no supported public TCP passive candidate on port 443") {
log.Warn("upstream lacks proxiable TCP candidates; falling back to direct connection")
sdp, tunnels, err = answer, nil, nil // apply the raw answer without proxying
}
if err != nil {
return err
} Prevention
- Before enabling the TCP proxy dialer, confirm the upstream advertises tcp passive port 443 host candidates
- Log candidate lines at debug level in new deployments to detect upstream ICE strategy changes
- Implement a fallback path that applies the unproxied answer when no proxyable candidate exists
When it happens
Trigger: Configuring the live media relay to dial the upstream through an HTTP CONNECT/SOCKS TCP proxy (proxyDialer != nil) while the upstream server's SDP contains no a=candidate ... tcp ... passive ... 443 host line.
Common situations: Upstream Codex endpoint changes its ICE strategy (e.g. prefers UDP-only or moves off port 443); a proxy environment where the server behind it advertises non-standard candidates; region-specific infrastructure differences.
Related errors
- upstream WebRTC TCP proxy candidate address must be an IP
- upstream WebRTC TCP proxy candidate is malformed
- upstream WebRTC offer is empty
- downstream WebRTC answer is empty
- Codex live TCP proxy listener returned an invalid address
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/b603531a20d3a52f.
Report an issue: GitHub.