router-for-me/CLIProxyAPI · error
create upstream WebRTC offer: %w
Error message
create upstream WebRTC offer: %w
What it means
Thrown when upstream.CreateOffer(nil) fails while generating the SDP offer to send to OpenAI. Pion CreateOffer errors when the connection state disallows offering (already closed/closing), when there are no media or data channels to describe, or on SDP marshaling failure. Here the DataChannel and audio track were just added, so state races dominate.
Source
Thrown at internal/client/codex/live/media.go:385
if errClose := channel.Close(); errClose != nil {
log.WithError(errClose).Debug("codex live media: close unsupported downstream DataChannel")
}
return
}
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, nilView on GitHub (pinned to 78f0c4079e)
Solutions
- Retry the full session (new NewSession) when the client remains connected
- Audit for goroutines that call session.Close() during setup (bridge failure handler fires 'data_channel_failed')
- Align pion/webrtc version to pick up offer-generation fixes
Defensive patterns
Strategy: retry
Try / catch
offer, errOffer := upstream.CreateOffer(nil)
if errOffer != nil {
if pcState := upstream.ConnectionState(); pcState == webrtc.PeerConnectionStateClosed {
return nil, "", fmt.Errorf("session closed before offer: %w", errOffer)
}
// transient: retry once after brief backoff
time.Sleep(50 * time.Millisecond)
offer, errOffer = upstream.CreateOffer(nil)
} Prevention
- Check upstream.ConnectionState() before offer creation in custom flows
- Serialize setup steps with session lifecycle (done channel) to avoid closed-state offers
- Retry at session granularity in callers
When it happens
Trigger: Upstream PC entered 'closed' state concurrently (session.Close raced setup), or internal SDP generation failure after adding the track/channel.
Common situations: Client disconnects mid-handshake causing teardown to race offer creation; rare pion internal errors.
Related errors
- set upstream WebRTC offer: %w
- create downstream WebRTC answer: %w
- set downstream WebRTC answer: %w
- upstream WebRTC offer is empty
- downstream WebRTC answer is empty
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/4dfecf1044548402.
Report an issue: GitHub.