router-for-me/CLIProxyAPI · error

create upstream DataChannel: %w

Error message

create upstream DataChannel: %w

What it means

Thrown when upstream.CreateDataChannel("oai-events", nil) fails while creating the OpenAI realtime events DataChannel on the upstream PeerConnection. Pion errors here when the SCTP transport is in an invalid state, the label/protocol exceeds limits, or too many channels exist. The session is closed on failure.

Source

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

	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 {
				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())

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Ensure AcceptUpstreamAnswer/NewSession are not racing with Close from disconnect handlers
  2. Retry session establishment once if the client reconnects immediately
  3. Upgrade pion/webrtc — SCTP state races have been patched across v4 minors
Defensive patterns

Strategy: retry

Try / catch

if _, _, err := relay.NewSession(ctx, offer, route); err != nil {
	var iceErr *webrtc.InvalidStateError
	if errors.As(err, &iceErr) {
		// PC state race — retry whole session once
		_, _, err = relay.NewSession(ctx, offer, route)
	}
}

Prevention

When it happens

Trigger: Calling CreateDataChannel on a PC whose SCTP association is already closing/closed (e.g. session torn down concurrently), or exceeding the 65534 channel limit (not realistic here).

Common situations: Race between session teardown (Close called from another goroutine) and setup; essentially a timing/concurrency edge rather than a config issue.

Related errors


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