nautechsystems/nautilus_trader · error
historical BinanceBar requests require EXTERNAL aggregation
Error message
historical BinanceBar requests require EXTERNAL aggregation
What it means
Historical BinanceBar requests are fulfilled from Binance's REST kline API, which returns externally (exchange) aggregated bars. Requesting bars whose aggregation source is Internal (locally aggregated) cannot be served by request_data and is rejected with anyhow::ensure!.
Solutions
- Build the bar type with AggregationSource::External for historical requests.
- Use the dedicated historical/request API that constructs EXTERNAL bar types for Binance klines.
- For internal aggregation, aggregate locally from streamed quotes/trades instead of requesting history.
Example fix
// before let bar_type = BarType::new(instrument_id, BarAggregation::Minute, PriceType::Last, AggregationSource::Internal); // after let bar_type = BarType::new(instrument_id, BarAggregation::Minute, PriceType::Last, AggregationSource::External);
Defensive patterns
Strategy: validation
Validate before calling
fn ensure_external_bars(bar_type: &BarType) -> Result<(), String> {
if bar_type.aggregation_source() == AggregationSource::External { Ok(()) }
else { Err("historical requests need EXTERNAL aggregation".into()) }
} Type guard
fn is_external_bar_type(bar_type: &BarType) -> bool {
bar_type.aggregation_source() == AggregationSource::External
} Try / catch
if is_external_bar_type(&bar_type) {
client.request_data(request)?;
} else {
log::warn!("skipping history request: internal bars not served by Binance REST");
} Prevention
- Always build bar types with AggregationSource::External for historical requests.
- Separate live-subscription bar types from history-request bar types.
- Add request-time validation in your request builder.
- Note Binance klines are always exchange-aggregated.
When it happens
Trigger: Calling request_data with a BinanceBar custom data type whose parsed bar_type.aggregation_source() is not AggregationSource::External, e.g. a bar type built with INTERNAL aggregation.
Common situations: Constructing bar types programmatically and forgetting to mark aggregation as external; reusing live-subscription bar types (internal aggregation) for historical requests.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- historical BinanceBar requests require LAST price type
- bar_type.aggregation_source must be External, was
- Binance does not support
- Binance Futures does not support
- Binance Futures does not support second-level kline…
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0a72ede1341fa72b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/binance/src/spot/data.rs:2258
}
}
Err(e) => log::error!("Instrument request failed: {e:?}"),
}
});
Ok(())
}
fn request_data(&self, request: RequestCustomData) -> anyhow::Result<()> {
if request.data_type.type_name() != "BinanceBar" {
log::warn!(
"Unsupported custom data request: {}",
request.data_type.type_name()
);
return Ok(());
}
let bar_type = parse_binance_bar_type(&request.data_type)?;
anyhow::ensure!(
bar_type.aggregation_source() == AggregationSource::External,
"historical BinanceBar requests require EXTERNAL aggregation"
);
anyhow::ensure!(
bar_type.spec().price_type == PriceType::Last,
"historical BinanceBar requests require LAST price type"
);
anyhow::ensure!(
bar_type.spec().is_time_aggregated(),
"historical BinanceBar requests require time aggregation"
);
let http = self.http_client.clone();
let sender = self.data_sender.clone();
let request_id = request.request_id;
let client_id = request.client_id;
let data_type = request.data_type;
let start = request.start;
let end = request.end;View on GitHub (pinned to 18893faf8b)