nautechsystems/nautilus_trader · error · anyhow::Error
historical BinanceBar requests require LAST price type
Error message
historical BinanceBar requests require LAST price type
What it means
Historical BinanceBar requests must use the LAST (trade) price type, since Binance klines are built from trades. Other price types (MID, BID, ASK) have no Binance REST kline equivalent, so the request is rejected after the aggregation-source check.
Solutions
- Set the bar spec price type to PriceType::Last for historical BinanceBar requests
- Use a different data request (e.g. quotes/ticks) if bid/ask-based history is needed
- Separate live bar configs (any price type, internal) from historical request configs (LAST, external)
Example fix
// before BarSpecification::new(1, BarAggregation::Minute, PriceType::Bid) // after BarSpecification::new(1, BarAggregation::Minute, PriceType::Last)
Defensive patterns
Strategy: validation
Validate before calling
fn can_request_binance_bar_history(bar_type: &BarType) -> bool {
bar_type.spec().price_type == PriceType::Last
} Type guard
fn is_last_price_bar(bt: &BarType) -> bool {
bt.spec().price_type == PriceType::Last
} Try / catch
match client.request_data(request) {
Err(e) if e.to_string().contains("LAST price type") => {
let last_bar = rebuild_bar_type(request.bar_type, PriceType::Last);
client.request_data(request.with_bar_type(last_bar))?;
}
r => r?,
} Prevention
- Use PriceType::Last for all Binance historical bar requests
- Treat bid/ask bars as internal-aggregation-only on Binance
- Validate bar specs (Last + External + time aggregation) before sending history requests
When it happens
Trigger: Sending RequestCustomData for "BinanceBar" where bar_type.spec().price_type is not PriceType::Last (e.g. Bid or Ask bars).
Common situations: Strategies using bid/ask bars live attempting the same bar type for backfill; generic historical-request code that forwards the strategy's configured price type; copying spot configs where quote-side bars exist.
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
- Derive candles are trade-based; only PriceType::Last is…
- historical BinanceBar requests require EXTERNAL aggregation
- Lighter candles only support LAST price type
- Only LAST price type bars are supported
- bar_type.aggregation_source must be External, was
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f623fff7b8170706.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/binance/src/futures/data.rs:2682
Ok(())
}
/// Requests Binance futures custom data.
///
/// Spawned fetch failures are logged and no response is emitted, matching
/// the existing request-path behavior for other Binance adapter requests.
fn request_data(&self, request: RequestCustomData) -> anyhow::Result<()> {
let data_type = request.data_type.clone();
let data_type_name = data_type.type_name().to_string();
if data_type_name == "BinanceBar" {
let bar_type = parse_binance_bar_type(&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 start = request.start;
let end = request.end;
let limit = request.limit.map(|value| value.get() as u32);
let params = request.params;
let clock = self.clock;
let venue = self.venue();
let start_nanos = datetime_to_unix_nanos(start);View on GitHub (pinned to 18893faf8b)