nautechsystems/nautilus_trader · error

no completed FX rollover batch to acknowledge

Error message

no completed FX rollover batch to acknowledge

What it means

Raised in the FX rollover module's `acknowledge` when `day.pending_adjustments` is None — there is no completed rollover batch awaiting acknowledgement. Pending adjustments are set when a batch completes and taken on acknowledgement; acknowledging without a batch is an ordering/lifecycle violation.

Source

Thrown at crates/backtest/src/modules/fx_rollover.rs:663

        let adjustments = batch.iter().map(|adjustment| adjustment.amount).collect();
        let mut day = self.rollover_day.borrow_mut();
        let day = day.as_mut().expect("rollover day initialized");
        day.pending_adjustments = Some(batch);
        day.pending_end_date = Some(batch_end_date);
        day.attempt_time = Some(ts_now);
        Ok(SimulationModuleResult::Completed(adjustments))
    }

    fn acknowledge(&self, outcomes: &[AccountAdjustmentOutcome]) -> anyhow::Result<()> {
        let (adjustments, attempt_time, batch_end_date) = {
            let mut day = self.rollover_day.borrow_mut();
            let day = day
                .as_mut()
                .ok_or_else(|| anyhow::anyhow!("FX rollover day is not initialized"))?;
            let adjustment_count = day
                .pending_adjustments
                .as_ref()
                .ok_or_else(|| anyhow::anyhow!("no completed FX rollover batch to acknowledge"))?
                .len();
            anyhow::ensure!(
                outcomes.len() == adjustment_count,
                "FX rollover acknowledgement count {}, expected {}",
                outcomes.len(),
                adjustment_count
            );
            let adjustments = day
                .pending_adjustments
                .take()
                .ok_or_else(|| anyhow::anyhow!("no completed FX rollover batch to acknowledge"))?;
            (
                adjustments,
                day.attempt_time
                    .take()
                    .ok_or_else(|| anyhow::anyhow!("FX rollover attempt time was not recorded"))?,
                day.pending_end_date.ok_or_else(|| {
                    anyhow::anyhow!("FX rollover batch end date was not recorded")

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Only acknowledge outcomes produced by a completed rollover batch in the same processing cycle.
  2. Track acknowledgement state in the driver to prevent duplicate ack calls.
  3. If outcomes were lost, re-run the rollover batch generation instead of acking stale results.
  4. Check that reset/init logic is not clearing pending state between batch completion and ack.

Example fix

// before
loop {
    engine.acknowledge(&outcomes)?; // retry re-acks same batch
}

// after
if !batch_acked {
    engine.acknowledge(&outcomes)?;
    batch_acked = true;
}
Defensive patterns

Strategy: type-guard

Validate before calling

anyhow::ensure!(engine.has_pending_fx_batch(), "no completed FX rollover batch; run process_rollover first");

Type guard

fn pending_fx_batch(engine: &FxRolloverModule) -> bool { engine.has_pending_batch() }

Try / catch

if let Err(e) = engine.acknowledge(&outcomes) {
    if e.to_string().contains("no completed FX rollover batch") {
        log::warn!("ack without batch; check driver event ordering");
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling `acknowledge` when no batch was completed for the day, calling it a second time for the same batch (first `take()` cleared it), or acking before `process_rollover` generated adjustments.

Common situations: Retry drivers that re-ack after failures; event pipelines delivering the ack out of order relative to batch completion; unit tests calling acknowledge directly without running the rollover pass.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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