Repository navigation
WebSocket.ping() on Android sends an empty binary frame instead of a protocol-level PING #57840
Description
Description
WebSocket.ping() on Android sends an empty binary data frame (opcode 0x2) via OkHttp's
client.send(ByteString.EMPTY), instead of a real RFC 6455 PING control frame (opcode 0x9). On iOS,
ping() correctly sends a protocol-level ping via SocketRocket's sendPing:error:.
This breaks against WebSocket servers that reject binary frames (e.g. AWS API Gateway WebSocket APIs),
which close the connection with code 1003 UNSUPPORTED_DATA instead of responding with a pong.
The incorrect ping() that sends the empty frame is still present on the latest version (v0.86.2) of RN here: https://github.com/react/react-native/blob/v0.86.2/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.kt#L327
try {
client.send(ByteString.EMPTY)
} catch (e: Exception) {
notifyWebSocketFailed(id, e.message)
}
Steps to reproduce
- Connect a WebSocket to a server that rejects binary frames (e.g. AWS API Gateway WS API).
- Call
webSocket.ping()on Android. - Observe the connection closes with
1003 UNSUPPORTED_DATAinstead of receiving a pong.
React Native Version
0.86.2
Affected Platforms
Runtime - Android
Output of npx @react-native-community/cli info
System:
OS: macOS 26.5.2
CPU: (12) arm64 Apple M4 Pro
Memory: 106.66 MB / 24.00 GB
Shell:
version: "5.9"
path: /opt/homebrew/bin/zsh
Binaries:
Node:
version: 23.10.0
path: /opt/homebrew/bin/node
Yarn:
version: 1.22.19
path: /opt/homebrew/bin/yarn
npm:
version: 10.9.2
path: /opt/homebrew/bin/npm
Watchman:
version: 2025.05.19.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods: Not Found
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.2
- iOS 26.2
- macOS 26.2
- tvOS 26.2
- visionOS 26.2
- watchOS 26.2
Android SDK: Not Found
IDEs:
Android Studio: 2024.2 AI-242.23726.103.2422.12816248
Xcode:
version: 26.2/17C52
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.14
path: /Users/inging/.jenv/shims/javac
Ruby: Not Found
npmPackages:
"@react-native-community/cli": Not Found
react: Not Found
react-native: Not Found
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Stacktrace or Logs
Logs from mitmproxy with a custom interceptor script:
<IP_REDACTED>:44604 -> WebSocket binary message -> <WSS_HOST_REDACTED>:443/
Error in WebSocket connection to <WSS_HOST_REDACTED>:443: WebSocket Error: UNSUPPORTED_DATA (reason: Binary is not supported)
MANDATORY Reproducer
https://gist.github.com/dekpient/4b611eb4efb58ecc1a881942f842a595
Screenshots and Videos
No response
Activity
react-native-bot commentedon Aug 5, 2026
Warning
Missing reproducer: We could not detect a reproducible example in your issue report. Reproducers are mandatory and we can accept only one of those as a valid reproducer:
You can read more about about it on our website: How to report a bug.
SnowingFox commentedon Aug 10, 2026
Triage finding: this can't be fixed in react-native without upstream OkHttp work
Confirmed the bug is still present on
main(WebSocketModule.kt:406—client.send(ByteString.EMPTY)sends a BINARY frame, opcode 0x2, not a PING control frame 0x9). iOS is correct (RCTWebSocketModule.mm→ SocketRocketsendPing:error:).Root cause is upstream, not RN:
okhttp3.WebSocketonly hasrequest()/queueSize()/send(String)/send(ByteString)/close()/cancel().send(ByteString)is hard-wired to opcode 0x2, so a protocol-level PING (0x9) is only reachable viaokhttp3.internal.ws.RealWebSocket.writePingFrame().writePingFrame()is meant to run only on the connection's serialized TaskRunner thread; RN'sping()runs on the JS bridge thread, so calling it races the writer and can interleave/corrupt frames on the socket. RN production code also never touchesokhttp3.internal.sendPing/onPongproposal) is still open/unmerged; maintainers' documented stance is "browsers don't do pings" (WebSocket ping logic is not customizable lysine-dev/okhttp#3197). So an OkHttp upgrade today would not help either.Options for maintainers:
ping()is undocumented (not part of the standard WebSocket API), so making it a no-op on Android is defensible — but it would not give AWS-keepalive users what they need.sendPing()on an OkHttp upgrade.This needs an upstream decision rather than an RN-only PR.
react-native-bot commentedon Sep 4, 2026
This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days.
react-native-bot commentedon Sep 28, 2026
This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days.