nautechsystems/nautilus_trader · warning · anyhow::Error

terminal report for {} has unaccounted fills; waiting for fi

Error message

terminal report for {} has unaccounted fills; waiting for fill reports

What it means

When processing an OrderStatusReport that is terminal (e.g. FILLED, CANCELED), the manager ensures the report's filled quantity accounts for all fills already known to the order. If terminal_report_has_missing_fills is true, there are unaccounted fills - the manager refuses to apply the terminal event and waits for the outstanding fill reports so no fill is lost.

Source

Thrown at crates/live/src/execution/manager.rs:4720

            &order_report,
            account_id,
            instrument,
            &[],
            true,
            None,
            None,
        );
        Some(events)
    }

    fn reconcile_order_report(
        &self,
        order: &OrderAny,
        report: &OrderStatusReport,
        instrument: Option<&InstrumentAny>,
        commission_client: Option<&dyn ExecutionClient>,
    ) -> anyhow::Result<Vec<OrderEventAny>> {
        anyhow::ensure!(
            !terminal_report_has_missing_fills(report, order.filled_qty()),
            "terminal report for {} has unaccounted fills; waiting for fill reports",
            order.client_order_id(),
        );
        let ts_now = self.clock.borrow().timestamp_ns();
        let commission = if matches!(
            report.order_status,
            OrderStatus::PartiallyFilled | OrderStatus::Filled
        ) && report.filled_qty > order.filled_qty()
            && let Some(instrument) = instrument
        {
            let fill_qty = report.filled_qty - order.filled_qty();
            Self::resolve_inferred_fill_commission(
                commission_client,
                instrument,
                fill_qty,
                incremental_inferred_fill_price_and_liquidity(order, report, instrument),
            )?

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the adapter delivers fill (trade) reports and that nothing drops them (check stream subscriptions)
  2. Retry/re-request the status report after fills arrive - the manager waits, so verify the fill stream is connected
  3. Check venue-specific ordering guarantees; if the venue sends FILLED status first, defer terminal handling until fills are in
  4. Review adapter reconciliation logic so status reports don't bypass fill reports

Example fix

// before (adapter skips individual trade reports)
if status.is_terminal() { self.generate_order_events(status); }
// after (emit fills first, let manager verify)
for fill in venue_fills { self.generate_fill_events(fill); }
self.generate_order_events(status);
Defensive patterns

Strategy: retry

Validate before calling

if terminal_report_has_missing_fills(&report, order.filled_qty()) {
    // wait for fill reports or re-request the status report later
}

Try / catch

match result {
    Err(e) if e.to_string().contains("unaccounted fills") => {
        // schedule re-request of the status report after fill reports arrive
    }
    other => other?,
}

Prevention

When it happens

Trigger: A status report arrives with a terminal status while the venue's fill reports for the executed quantity haven't all been received/processed yet (e.g. FILLED status seen before the corresponding TradeReports).

Common situations: Venues that emit order status updates and trade fills over separate streams with different latencies; reconciliation snapshots taken mid-flight; adapters that suppress individual fill reports and rely only on status reports.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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