router-for-me/CLIProxyAPI · error
add upstream audio track: %w
Error message
add upstream audio track: %w
What it means
Thrown when upstream.AddTrack(toOpenAI) fails attaching the OpenAI-facing audio sender. Unlike the downstream leg, there is no remote offer yet on upstream at this point, so failure typically comes from internal sender-state errors or repeated AddTrack with the same track ID in a degraded session rather than codec negotiation.
Source
Thrown at internal/client/codex/live/media.go:349
_ = session.Close()
return nil, "", fmt.Errorf("create downstream audio track: %w", errTrack)
}
downstreamSender, errTrack := downstream.AddTrack(toDesktop)
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("add downstream audio track: %w", errTrack)
}
go drainRTCP("downstream", downstreamSender, session.done)
toOpenAI, errTrack := webrtc.NewTrackLocalStaticRTP(opusCodec, "audio", "codex-live")
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("create upstream audio track: %w", errTrack)
}
upstreamSender, errTrack := upstream.AddTrack(toOpenAI)
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("add upstream audio track: %w", errTrack)
}
go drainRTCP("upstream", upstreamSender, session.done)
downstream.OnTrack(func(track *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
if !strings.EqualFold(track.Codec().MimeType, webrtc.MimeTypeOpus) {
return
}
go relayRTP("downstream-to-upstream", track, toOpenAI, session.done)
})
upstream.OnTrack(func(track *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
if !strings.EqualFold(track.Codec().MimeType, webrtc.MimeTypeOpus) {
return
}
go relayRTP("upstream-to-downstream", track, toDesktop, session.done)
})
downstream.OnDataChannel(func(channel *webrtc.DataChannel) {
if channel.Label() != realtimeDataChannelLabel {
if errClose := channel.Close(); errClose != nil {View on GitHub (pinned to 78f0c4079e)
Solutions
- Retry the whole session establishment (NewSession) — setup is atomic and cleans up on failure
- Check pion logs for the underlying RTPSender error to distinguish resource vs state causes
- Keep pion/webrtc at a patched version (older v4 releases had sender race fixes)
Defensive patterns
Strategy: retry
Try / catch
if _, _, err := relay.NewSession(ctx, offer, route); err != nil {
if strings.Contains(err.Error(), "add upstream audio track") && ctx.Err() == nil {
_, _, err = relay.NewSession(ctx, offer, route) // setup is atomic; safe to retry
}
} Prevention
- Depend on NewSession's atomic cleanup semantics for retries
- Track failure rate; sustained failures indicate environment problems, not transient ones
- Stay current on pion v4 patch releases
When it happens
Trigger: Internal RTP sender creation failure on the upstream PeerConnection, or state corruption from an earlier partial setup on the same PC.
Common situations: Rare in practice; usually preceded by other setup anomalies. Retryable at the session level since NewSession is atomic per attempt.
Related errors
- create downstream audio track: %w
- add downstream audio track: %w
- create upstream audio track: %w
- create upstream PeerConnection: %w
- set upstream WebRTC answer: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/c7add8513bc1befe.
Report an issue: GitHub.