fix(futures-ws): reject mixed-category combined streams#991
Merged
carlosmiei merged 3 commits intoJun 3, 2026
Conversation
Binance's USDⓈ-M futures WebSocket split (2026-03-06) routes streams to separate /public, /market and /private endpoints and will not push cross-category streams on a single connection. futuresSubscribe() picked the routing category from streams[0] only, so a combined subscription mixing e.g. @aggTrade (market) and @Depth (public) routed everything to one endpoint and silently dropped data for the other category. Validate that every stream in a combined subscription shares the same category and throw a descriptive error otherwise, so callers fail loudly and subscribe per category (also Binance's recommendation). All built-in helpers already build homogeneous arrays, so none are affected.
The ws-endpoints-migration test file (added in ccxt#985) was never wired into any npm script or CI step, so its assertions — including the new mixed-category guard — never gated PRs. Add a `ws-tests-migration` script that runs only the hermetic (non-"Live:") describes, no network or API keys required, and invoke it from the CI workflow.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a safety check to USDⓈ-M futures combined WebSocket subscriptions so callers cannot combine streams that Binance routes to different /public, /market, and /private endpoints (preventing silent data loss after the 2026 endpoint split).
Changes:
- Add a mixed-category validation guard in
futuresSubscribe()that throws a descriptive error for cross-category stream arrays. - Add hermetic unit tests covering market+public and public+private mixed subscriptions, plus basic error-message assertions.
- Add an npm script and CI workflow step to run the non-live migration test subset.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/node-binance-api.ts |
Adds category-consistency validation for combined futures subscriptions before opening a WebSocket. |
tests/ws-endpoints-migration.test.ts |
Adds tests ensuring futuresSubscribe() rejects mixed-category combined streams. |
package.json |
Introduces ws-tests-migration script to run non-live migration tests only. |
.github/workflows/js.yml |
Runs the new migration test script in CI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The USDⓈ-M Futures WebSocket split (Important WebSocket Change Notice, 2026-03-06) routes streams to three separate endpoints by data type:
/public—@bookTicker,!bookTicker,@depth*/market—@aggTrade,@markPrice, kline,@ticker,@miniTicker,@forceOrder,@compositeIndex,!contractInfo,@assetIndex/private— user data (listenKey)Binance will not push cross-category streams on a single connection — and legacy unrouted URLs were decommissioned 2026-04-23.
futuresSubscribe()derives the routing category fromstreams[0]only:So a combined subscription that mixes categories — e.g.
futuresSubscribe(['btcusdt@aggTrade', 'btcusdt@depth'], cb)— routes the whole connection to/market(from@aggTrade), and the/public@depthstream silently receives no data. No error, just missing data.Fix
Validate that every stream in a combined subscription resolves to the same category; throw a descriptive error otherwise. Callers then fail loudly and subscribe per category — which is also Binance's own recommendation (one connection per traffic type).
All built-in helpers (
futuresAggTradeStream,futuresCandlesticksStream,futuresChart, etc.) build homogeneous stream arrays, so none are affected — this only guards advanced/directfuturesSubscribe([...])calls that mix categories.Tests
Added hermetic tests (no sockets opened — the guard runs before
new WebSocket) totests/ws-endpoints-migration.test.tscovering market+public, public+private, and the error-message contents. Full non-live suite: 29 passing;tsc --noEmitclean.