nautechsystems/nautilus_trader · error · IncompleteOrderReports

IncompleteOrderReports: {detail}

Error message

IncompleteOrderReports: {detail}

What it means

Helper constructor for the IncompleteOrderReports error type: thrown when Lighter order-status report reconciliation yields fewer/incorrect reports than expected (e.g. generating batch submit results where a position/status report is missing). The reports gathered so far are carried in the error so callers can inspect what was recovered, and `detail` explains the discrepancy.

Source

Thrown at crates/adapters/lighter/src/execution.rs:5145

// account, so a market-scoped sweep can serve nothing while older trades for that
// market have already been evicted by newer trades in other markets.
struct FillSweep {
    reports: Vec<FillReport>,
    covers_window: bool,
}

#[derive(Debug, thiserror::Error)]
#[error("incomplete Lighter order reports: {detail}")]
struct IncompleteOrderReports {
    reports: Vec<OrderStatusReport>,
    detail: String,
}

fn incomplete_order_reports(
    reports: Vec<OrderStatusReport>,
    detail: impl Into<String>,
) -> anyhow::Error {
    anyhow::Error::new(IncompleteOrderReports {
        reports,
        detail: detail.into(),
    })
}

fn partial_order_reports(error: &anyhow::Error) -> Vec<OrderStatusReport> {
    error
        .downcast_ref::<IncompleteOrderReports>()
        .map(|incomplete| incomplete.reports.clone())
        .unwrap_or_default()
}

fn is_commission_error(error: &anyhow::Error) -> bool {
    error
        .chain()
        .any(|cause| cause.downcast_ref::<LighterCommissionError>().is_some())
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the `detail` and the carried reports to see which orders are incomplete.
  2. Re-query the venue for the missing order IDs after a short delay and reconcile again.
  3. Check that client_order_id <-> venue order id mappings in the cache are intact.
  4. Retry reconciliation; transient light-out gaps on Lighter commonly cause partial report sets.

Example fix

// before
let reports = client.generate_order_status_reports(&ids).await?; // may be IncompleteOrderReports
// after
match client.generate_order_status_reports(&ids).await { Err(e) if is_incomplete(&e) => { sleep(RETRY).await; client.generate_order_status_reports(&ids).await } r => r }
Defensive patterns

Strategy: retry

Try / catch

match client.generate_order_status_reports(&ids).await {
    Err(e) if format!("{e:#}").contains("IncompleteOrderReports") => {
        tokio::time::sleep(RECONCILE_DELAY).await;
        client.generate_order_status_reports(&ids).await?; // re-query missing reports
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calls to incomplete_order_reports(reports, detail) — e.g. when generating order status reports or submit results and some orders lack a matching status report from the venue (missing/None report, cancelled mid-reconcile, or venue returned partial data).

Common situations: Requesting open-orders/status during venue instability, orders whose market_id cannot be mapped, or polling status immediately after submission before the venue persists the order.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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