Skip to content

fix(futures-ws): reject mixed-category combined streams#991

Merged
carlosmiei merged 3 commits into
ccxt:masterfrom
pcriadoperez:futures-ws-mixed-category-guard
Jun 3, 2026
Merged

fix(futures-ws): reject mixed-category combined streams#991
carlosmiei merged 3 commits into
ccxt:masterfrom
pcriadoperez:futures-ws-mixed-category-guard

Conversation

@pcriadoperez
Copy link
Copy Markdown
Collaborator

@pcriadoperez pcriadoperez commented Jun 1, 2026

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 from streams[0] only:

const category = this.classifyFuturesStream(streams[0]);
const baseUrl = this.getFStreamUrl(category);

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 @depth stream 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).

futuresSubscribe: cannot combine 'market' stream "btcusdt@aggTrade" with 'public' stream "btcusdt@depth" on one connection. Binance routes futures streams to separate /public, /market and /private endpoints; subscribe to each category separately.

All built-in helpers (futuresAggTradeStream, futuresCandlesticksStream, futuresChart, etc.) build homogeneous stream arrays, so none are affected — this only guards advanced/direct futuresSubscribe([...]) calls that mix categories.

Tests

Added hermetic tests (no sockets opened — the guard runs before new WebSocket) to tests/ws-endpoints-migration.test.ts covering market+public, public+private, and the error-message contents. Full non-live suite: 29 passing; tsc --noEmit clean.

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.
@pcriadoperez pcriadoperez marked this pull request as ready for review June 3, 2026 09:30
@pcriadoperez pcriadoperez requested a review from Copilot June 3, 2026 09:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/node-binance-api.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@carlosmiei carlosmiei closed this Jun 3, 2026
@carlosmiei carlosmiei reopened this Jun 3, 2026
@carlosmiei carlosmiei self-assigned this Jun 3, 2026
@carlosmiei carlosmiei merged commit 8262f79 into ccxt:master Jun 3, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants