nautechsystems/nautilus_trader · error · anyhow::Error
fill report start time must not exceed end time
Error message
fill report start time must not exceed end time
What it means
generate_fill_reports validates the requested window before querying /fapi/v1/userTrades: the start time (ms) must not exceed the effective end time, where end defaults to the current clock time when cmd.end is None. An inverted range would paginate meaningless windows, so the client fails fast. This mirrors guards common to all historical-report generators that take start/end pairs.
Source
Thrown at crates/adapters/binance/src/futures/execution.rs:1994
) -> anyhow::Result<Vec<FillReport>> {
let Some(instrument_id) = cmd.instrument_id else {
log::warn!("generate_fill_reports requires instrument_id for Binance Futures");
return Ok(Vec::new());
};
let symbol = format_binance_symbol(&instrument_id);
let mut trades = Vec::new();
let mut seen_trade_ids = AHashSet::new();
let requested_end_time = cmd
.end
.map(|end| end.as_i64() / NANOSECONDS_IN_MILLISECOND as i64);
if let Some(start) = cmd.start {
let query_start_time = start.as_i64() / NANOSECONDS_IN_MILLISECOND as i64;
let query_end_time = requested_end_time.unwrap_or_else(|| {
self.clock.get_time_ns().as_i64() / NANOSECONDS_IN_MILLISECOND as i64
});
anyhow::ensure!(
query_start_time <= query_end_time,
"fill report start time must not exceed end time"
);
let mut window_start = query_start_time;
loop {
let window_end = window_start
.saturating_add(USER_TRADES_MAX_INTERVAL_MS)
.min(query_end_time);
let mut from_id = None;
loop {
let mut builder = BinanceUserTradesParamsBuilder::default();
builder.symbol(symbol.clone());
builder.limit(USER_TRADES_PAGE_LIMIT);
if let Some(cursor) = from_id {
builder.from_id(cursor);View on GitHub (pinned to a4b06ed870)
Solutions
- Order the arguments so start <= end and validate before issuing the report
- When end is None, ensure start is in the past relative to the host clock
- Normalize/clamp the range (e.g. swap if inverted) in the code that builds the report command
Example fix
// before
let report = client
.generate_fill_reports(GenerateFillReports::new(account_id, Some(future_start), None))
.await?;
// after
let report = client
.generate_fill_reports(GenerateFillReports::new(account_id, Some(past_start), Some(later_end)))
.await?; Defensive patterns
Strategy: validation
Validate before calling
let start_ms = cmd.start.map(|t| t.as_i64() / 1_000_000);
let end_ms = cmd.end.map(|t| t.as_i64() / 1_000_000)
.unwrap_or_else(|| clock.get_time_ns().as_i64() / 1_000_000);
if let Some(s) = start_ms {
anyhow::ensure!(s <= end_ms, "inverted fill-report window");
} Type guard
fn valid_report_window(start_ms: i64, end_ms: i64) -> bool {
start_ms <= end_ms
} Prevention
- Clamp report ranges server-side: start = min(start, end), both <= now
- Use a single clock/timezone source when building report windows
- Log both timestamps when dispatching report commands to diagnose skew
When it happens
Trigger: Issuing GenerateFillReports with start > end, or with a future start and end omitted (since end then defaults to now, any start in the future trips the guard); also start/end swapped in caller code.
Common situations: Clock skew between the caller and the client host; datetime conversions mixing timezones so start lands after end; reconciliation code passing a session window the wrong way round.
Related errors
- Binance user-trades pagination made no progress
- Binance historical bars require time aggregation
- invalid Binance Futures order-book depth {depth}; valid valu
- Binance Futures ticker custom data requires BINANCE venue in
- BinanceFuturesExecutionClient requires UsdM or CoinM product
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/f634919fd759e50b.
Report an issue: GitHub.