router-for-me/CLIProxyAPI · error
set upstream WebRTC offer: %w
Error message
set upstream WebRTC offer: %w
What it means
Thrown when upstream.SetLocalDescription(offer) fails while committing the locally generated offer. After SetLocalDescription, ICE candidate gathering begins (the gatherComplete promise below). Pion fails this when the description state is inconsistent (offer already set, PC closing) or the SDP cannot be re-parsed — typically a state race with session teardown.
Source
Thrown at internal/client/codex/live/media.go:389
}
session.bridge.attachDownstream(channel)
})
upstreamChannel, errChannel := upstream.CreateDataChannel(realtimeDataChannelLabel, nil)
if errChannel != nil {
_ = session.Close()
return nil, "", fmt.Errorf("create upstream DataChannel: %w", errChannel)
}
session.bridge.attachUpstream(upstreamChannel)
gatherComplete := webrtc.GatheringCompletePromise(upstream)
offer, errOffer := upstream.CreateOffer(nil)
if errOffer != nil {
_ = session.Close()
return nil, "", fmt.Errorf("create upstream WebRTC offer: %w", errOffer)
}
if errLocal := upstream.SetLocalDescription(offer); errLocal != nil {
_ = session.Close()
return nil, "", fmt.Errorf("set upstream WebRTC offer: %w", errLocal)
}
select {
case <-gatherComplete:
case <-ctx.Done():
_ = session.Close()
return nil, "", fmt.Errorf("gather upstream WebRTC candidates: %w", ctx.Err())
}
localDescription := upstream.LocalDescription()
if localDescription == nil || strings.TrimSpace(localDescription.SDP) == "" {
_ = session.Close()
return nil, "", errors.New("upstream WebRTC offer is empty")
}
session.localOffer = localDescription.SDP
return session, localDescription.SDP, nil
}
func (s *pionMediaSession) AcceptUpstreamAnswer(ctx context.Context, upstreamAnswer string) (string, error) {
if s == nil || s.upstream == nil || s.downstream == nil {View on GitHub (pinned to 78f0c4079e)
Solutions
- Retry session establishment if the client is still connected
- Ensure handshake timeouts do not close the session before SetLocalDescription completes
- Keep pion/webrtc current for ICE-agent state race fixes
Defensive patterns
Strategy: retry
Try / catch
if errLocal := upstream.SetLocalDescription(offer); errLocal != nil {
if upstream.ConnectionState() == webrtc.PeerConnectionStateClosed {
return nil, "", fmt.Errorf("upstream closed during offer commit: %w", errLocal)
}
return nil, "", errLocal
} Prevention
- Set local description immediately after CreateOffer with no await points in between
- Ensure handshake timeouts exceed worst-case setup time
- Treat repeated occurrences as a teardown-race bug in caller lifecycle management
When it happens
Trigger: Concurrent Close() during setup, double SetLocalDescription, or ICE agent shutdown initiated between CreateOffer and SetLocalDescription.
Common situations: Handshake-timeout handlers firing too aggressively and tearing down the session mid-offer; client cancellation racing setup.
Related errors
- set downstream WebRTC answer: %w
- SDP contains incomplete ICE credentials
- SDP contains inconsistent bundled ICE credentials
- create upstream WebRTC offer: %w
- create downstream WebRTC answer: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/9623bc5557f77b9e.
Report an issue: GitHub.