Skip to content

performRpc can stall under degraded network on React Native/iOS in livekit-client 2.18.x #1937

Description

@zkewal

Describe the bug

What I'm expecting

Reliable performRpc() calls should either:

  • succeed under temporary network degradation, or
  • fail explicitly with a timeout / reconnect-related error.

After the network recovers, the room should recover without requiring a reconnect or joining a new room.

What happens instead

In our React Native iOS app, after upgrading livekit-client from 2.15.8 to 2.18.3 / 2.18.4, reliable RPC calls can stop reaching the backend after mild or moderate mid-session network degradation.

The room starts healthy and RPCs work normally at first. After enabling network degradation and sending a few RPCs, one RPC can get stuck before the request is actually sent:

  • the backend never receives the RPC request
  • the request does not appear to enter normal local ACK / response tracking
  • reconnecting or joining a new room restores behavior immediately

This is blocking our upgrade from the older LiveKit client stack.

Reproduction

I do not yet have a minimal standalone repro repository, but the shortest app-level repro I have is:

  1. Use a React Native iOS app with one of these dependency sets:

    • @livekit/react-native 2.9.2
    • @livekit/react-native-webrtc 137.0.2
    • livekit-client 2.18.4

    or

    • @livekit/react-native 2.9.6
    • @livekit/react-native-webrtc 137.0.2
    • livekit-client 2.18.3
  2. Connect to a room with a remote participant or backend participant that registers a simple RPC handler.

  3. From the local participant, repeatedly call performRpc().

await room.localParticipant.performRpc({
  destinationIdentity,
  method: 'ping',
  payload: '',
});
  1. Start on a healthy network and confirm RPC works normally.
  2. After the room is connected and stable, enable Network Link Conditioner with mild or moderate degradation (added latency / loss).
  3. Continue sending RPCs for a few turns while the degraded network is active.
  4. In the bad state, one RPC eventually hangs before send:
    • the remote side never receives the request
    • the local app does not see the request enter its normal pending ACK / pending response bookkeeping
  5. Disable the network conditioner.
  6. The stuck state can persist until reconnecting or joining a new room.

Known non-repro / good stack:

  • @livekit/react-native 2.9.2
  • @livekit/react-native-webrtc 137.0.2
  • livekit-client 2.15.8

Logs

I do not yet have a minimal standalone repro log with `setLogLevel('debug')` enabled from app startup.

What our app-level instrumentation consistently shows for the stuck request:
- `performRpc()` is entered
- the backend never logs or receives the RPC request
- the local request never appears to enter normal pending ACK / pending response tracking
- reconnecting or joining a new room restores RPC delivery immediately

If useful, I can follow up with a cleaner repro run that adds temporary logging around:
- `sendDataPacket(..., RELIABLE)`
- `waitForBufferStatusLow()`
- reliable data channel `bufferedAmount`
- reliable data channel `readyState`

System Info

Client runtime: React Native iOS app (not browser)
Browser: N/A

Dev machine:
ProductName: macOS
ProductVersion: 26.4.1
BuildVersion: 25E253

Node: v22.22.1
Yarn: 4.12.0

Known good stack:
@livekit/react-native: 2.9.2
@livekit/react-native-webrtc: 137.0.2
livekit-client: 2.15.8

Known bad stack:
@livekit/react-native: 2.9.2
@livekit/react-native-webrtc: 137.0.2
livekit-client: 2.18.4

Known bad stack:
@livekit/react-native: 2.9.6
@livekit/react-native-webrtc: 137.0.2
livekit-client: 2.18.3

Severity

blocking an upgrade

Additional Information

A few points that may help with triage:

  • The same React Native wrapper version can be either good or bad depending on the resolved livekit-client version.

    • good: @livekit/react-native 2.9.2 + livekit-client 2.15.8
    • bad: @livekit/react-native 2.9.2 + livekit-client 2.18.4
      This is the main reason I believe this issue belongs in client-sdk-js rather than client-sdk-react-native.
  • From source review, the most suspicious regression window is between 2.15.8 and 2.18.x, especially around:

    • 8777025c - Wait for dc buffer status low for all published packets (#1691)
    • d6306572 - Add new rtc path with implicit single peer connection mode (#1785)
  • The behavior matches a failure mode where performRpc() stalls before the reliable data channel send completes:

    • performRpc() registers pending ACK / response handlers only after publishRpcRequest() returns
    • in newer versions, reliable sendDataPacket() waits on waitForBufferStatusLow() before dc.send(...)
    • if that wait stalls under degraded transport, the RPC never reaches the backend and no normal RPC timeout bookkeeping is installed
  • I have not yet re-tested on the absolute latest livekit-client release. If needed, I can do that and also provide a smaller repro with debug logging enabled from process startup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions