router-for-me/CLIProxyAPI · error

set downstream WebRTC offer: %w

Error message

set downstream WebRTC offer: %w

What it means

Thrown when downstream.SetRemoteDescription fails while applying the client's WebRTC offer SDP to the downstream PeerConnection. Pion rejects offers that are not valid SDP, use an incompatible SDP semantics (unified-plan vs plan-b), or reference media the MediaEngine cannot negotiate (here: audio-only Opus). The half-built session is closed via session.Close().

Source

Thrown at internal/client/codex/live/media.go:326

		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")

	if errRemote := downstream.SetRemoteDescription(webrtc.SessionDescription{
		Type: webrtc.SDPTypeOffer,
		SDP:  clientOffer,
	}); errRemote != nil {
		_ = session.Close()
		return nil, "", fmt.Errorf("set downstream WebRTC offer: %w", errRemote)
	}

	toDesktop, errTrack := webrtc.NewTrackLocalStaticRTP(opusCodec, "audio", "codex-live")
	if errTrack != nil {
		_ = 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)

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Confirm the client offer is a complete, base64/JSON-encoded SDP of type 'offer'
  2. Restrict clients to audio-only Opus sessions — the relay registers no video codecs
  3. Log the offer's m-lines at debug level to identify unsupported media
  4. Update the client WebRTC stack to a unified-plan capable version
Defensive patterns

Strategy: validation

Validate before calling

func isValidAudioOffer(sdp string) bool {
	parsed := sdp.Unmarshal // use sdp/3rd-party parser; simplified check:
	return strings.Contains(sdp, "m=audio") && strings.Contains(sdp, "opus")
}

Try / catch

if _, _, err := relay.NewSession(ctx, clientOffer, route); err != nil {
	if strings.Contains(err.Error(), "set downstream WebRTC offer") {
		// reject the client with 400 rather than 500: the offer is unusable
		respondBadRequest(w)
		return
	}
}

Prevention

When it happens

Trigger: clientOffer is empty, truncated, or not an SDP; the offer carries video m-lines or codecs the engine (Opus/111 only) cannot answer; SDP session-level parse failure.

Common situations: A client SDK or non-audio client sending video/screen-share offers, a corrupted offer passed through an intermediate transport, or a client library that emits plan-b SDP.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/28e88df01abfaba2. Report an issue: GitHub.