nautechsystems/nautilus_trader · error
Binance Spot kline subscriptions require JSON market-data…
Error message
Binance Spot kline subscriptions require JSON market-data mode
What it means
Bar (kline) subscriptions on Binance Spot are only available in JSON market-data mode, because kline streams are delivered via the public JSON WebSocket. The client rejects subscribe_bars when running in SBE mode.
Solutions
- Set the Spot data client market-data mode to BinanceSpotMarketDataMode::Json in the adapter config.
- Alternatively obtain bars via internal aggregation (subscribe quotes/trades and let the engine aggregate) instead of external kline streams.
- Verify the mode before building strategies that need klines.
Example fix
// before config.spot_market_data_mode = BinanceSpotMarketDataMode::Sbe; // after config.spot_market_data_mode = BinanceSpotMarketDataMode::Json; // required for kline subscriptions
Defensive patterns
Strategy: validation
Validate before calling
fn bars_require_json_mode(mode: BinanceSpotMarketDataMode) -> Result<(), String> {
if mode == BinanceSpotMarketDataMode::Json { Ok(()) } else { Err("klines require JSON market-data mode".into()) }
} Try / catch
match client.subscribe_bars(cmd) {
Err(e) if e.to_string().contains("require JSON market-data mode") => {
log::warn!("restart adapter in JSON mode or aggregate bars internally");
}
r => r?,
} Prevention
- Choose market-data mode based on all data types strategies need (bars => JSON).
- Validate mode vs data requirements during node config load.
- Prefer internal aggregation for bars if SBE mode is mandatory.
- Document the mode/data-type matrix for the adapter.
When it happens
Trigger: Calling subscribe_bars while spot_market_data_mode == Sbe, e.g. the adapter was configured with SBE market data and a strategy requests bar subscriptions.
Common situations: Running an SBE-configured data client and adding a bar-based strategy; defaults to SBE mode in config while strategy needs klines; switching data types without revisiting mode config.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Binance Spot 24-hour ticker custom data requires JSON…
- Binance does not support
- Binance Futures does not support
- Binance Futures does not support second-level kline…
- Binance Futures supports L1_MBP and L2_MBP order book…
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e1b2c83aa4339958.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/binance/src/spot/data.rs:1974
fn subscribe_trades(&mut self, cmd: SubscribeTrades) -> anyhow::Result<()> {
let instrument_id = cmd.instrument_id;
let ws = self.ws_client.clone();
let stream = format!("{}@trade", instrument_id.symbol.as_str().to_lowercase());
self.spawn_ws(
async move {
ws.subscribe(vec![stream])
.await
.context("trades subscription")
},
"trade subscription",
);
Ok(())
}
fn subscribe_bars(&mut self, cmd: SubscribeBars) -> anyhow::Result<()> {
anyhow::ensure!(
self.spot_market_data_mode == BinanceSpotMarketDataMode::Json,
"Binance Spot kline subscriptions require JSON market-data mode"
);
let bar_type = cmd.bar_type;
let ws = self.ws_client.clone();
let interval = bar_spec_to_binance_interval(bar_type.spec())?;
let stream = format!(
"{}@kline_{}",
bar_type.instrument_id().symbol.as_str().to_lowercase(),
interval.as_str()
);
self.spawn_ws(
async move {
ws.subscribe(vec![stream])
.await
.context("bars subscription")View on GitHub (pinned to 18893faf8b)