nautechsystems/nautilus_trader · error

Failed to parse fill report for {}: {e}

Error message

Failed to parse fill report for {}: {e}

What it means

While generating fill (execution) reports from listCurrentOrders/cleared orders, the placed_date timestamp on each Betfair order must be parsed by parse_betfair_timestamp. An unparseable timestamp aborts the fill report for that bet_id with this wrapped error.

Source

Thrown at crates/adapters/betfair/src/execution.rs:4249

    orders: &[CurrentOrderSummary],
    fill_tracker: &mut FillTracker,
    customer_order_refs: &AHashMap<String, CustomerOrderRefResolution>,
    account_id: AccountId,
    currency: Currency,
    ts_init: UnixNanos,
) -> anyhow::Result<Vec<FillReport>> {
    let mut reports = Vec::new();

    for order in orders {
        let size_matched = order.size_matched.unwrap_or(Decimal::ZERO);
        let size_voided = order.size_voided.unwrap_or(Decimal::ZERO);
        let gross_matched = size_matched + size_voided;
        if gross_matched == Decimal::ZERO {
            continue;
        }

        parse_betfair_timestamp(&order.placed_date).map_err(|e| {
            anyhow::anyhow!("Failed to parse fill report for {}: {e}", order.bet_id)
        })?;

        let has_applied_fill_lots = fill_tracker.has_fill_lots(&order.bet_id);
        let cumulative = if has_applied_fill_lots {
            gross_matched
        } else {
            size_matched
        };
        let incremental_fill = if has_applied_fill_lots && size_voided > Decimal::ZERO {
            fill_tracker.advance_cumulative_fill_with_voids(
                &order.bet_id,
                cumulative,
                size_voided,
                order.average_price_matched,
                order.price_size.price,
            )
        } else {
            fill_tracker.advance_cumulative_fill(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log the raw placed_date value for the reported bet_id and compare against the expected format.
  2. Extend parse_betfair_timestamp to accept the observed format (e.g. fractional seconds present or absent).
  3. Skip or default the timestamp for records where placed_date is legitimately absent, if business-appropriate.

Example fix

// before
parse_betfair_timestamp(&order.placed_date).map_err(|e| anyhow::anyhow!("Failed to parse fill report for {}: {e}", order.bet_id))?;

// after
let ts = if order.placed_date.is_empty() {
    ts_init
} else {
    parse_betfair_timestamp(&order.placed_date).map_err(|e| anyhow::anyhow!("Failed to parse fill report for {}: {e}", order.bet_id))?
};
Defensive patterns

Strategy: validation

Validate before calling

// guard before report generation
let ts = parse_betfair_timestamp(&order.placed_date)
    .inspect_err(|e| tracing::warn!("bet {} bad placed_date {:?}: {e}", order.bet_id, order.placed_date));

Try / catch

match client.generate_fill_reports().await {
    Ok(fills) => apply(fills),
    Err(e) if e.to_string().contains("Failed to parse fill report") => {
        tracing::error!("fill timestamp parse failure: {e:#}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A Betfair order record has a placed_date string that fails timestamp parsing (wrong format, missing value, unexpected timezone representation) during fill report generation.

Common situations: Betfair changing date serialization; null/empty placed_date on unusual order records; locale-dependent date formats.

Understand the failure class

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/a4abd3b4bb696b51. Report an issue: GitHub.