nautechsystems/nautilus_trader · error
no completed CFD swap batch to acknowledge
Error message
no completed CFD swap batch to acknowledge
What it means
acknowledge() requires that a completed batch of pending adjustments exists to match the supplied outcomes against. If rollover_day exists but pending_adjustments is None, there is no completed batch to acknowledge and this error is thrown.
Source
Thrown at crates/backtest/src/modules/cfd_swap.rs:458
let mut day = self.rollover_day.borrow_mut();
let day = day
.as_mut()
.ok_or_else(|| anyhow::anyhow!("CFD swap rollover day is not initialized"))?;
day.pending_adjustments = Some(batch);
day.pending_end_date = Some(batch_end_date);
Ok(SimulationModuleResult::Completed(adjustments))
}
fn acknowledge(&self, outcomes: &[AccountAdjustmentOutcome]) -> anyhow::Result<()> {
let (adjustments, batch_end_date) = {
let mut day = self.rollover_day.borrow_mut();
let day = day
.as_mut()
.ok_or_else(|| anyhow::anyhow!("CFD swap rollover day is not initialized"))?;
let adjustment_count = day
.pending_adjustments
.as_ref()
.ok_or_else(|| anyhow::anyhow!("no completed CFD swap batch to acknowledge"))?
.len();
anyhow::ensure!(
outcomes.len() == adjustment_count,
"CFD swap acknowledgement count {}, expected {}",
outcomes.len(),
adjustment_count
);
let adjustments = day
.pending_adjustments
.take()
.ok_or_else(|| anyhow::anyhow!("no completed CFD swap batch to acknowledge"))?;
let end_date = day
.pending_end_date
.ok_or_else(|| anyhow::anyhow!("CFD swap batch end date was not recorded"))?;
(adjustments, end_date)
};
let mut failed = Vec::new();View on GitHub (pinned to 18893faf8b)
Solutions
- Acknowledge exactly once per Completed result from process()
- Track batch lifecycle in your engine wrapper: only call acknowledge when the preceding process returned Completed
- If retrying after a failure, re-run process() to regenerate the batch before acknowledging
Example fix
// before: double acknowledge module.acknowledge(&outcomes)?; module.acknowledge(&outcomes)?; // pending already consumed // after module.acknowledge(&outcomes)?; // once per Completed batch
Defensive patterns
Strategy: validation
Validate before calling
// guard: only acknowledge a batch you actually received
let batch: Option<Vec<Money>> = match module.process(ts_now)? {
SimulationModuleResult::Completed(a) => Some(a),
_ => None,
};
if let Some(amounts) = batch { /* acknowledge */ } Type guard
fn batch_ready(r: &SimulationModuleResult) -> Option<&[Money]> {
match r { SimulationModuleResult::Completed(a) => Some(a), _ => None }
} Try / catch
match module.acknowledge(&outcomes) {
Err(e) if e.to_string().contains("no completed CFD swap batch") => {
log::warn!("acknowledge called without a completed batch");
Ok(())
}
other => other,
} Prevention
- One acknowledge per Completed batch; never retry-acknowledge without re-running process
- Sequence engine events so acknowledge cannot arrive before process completes
- In tests, always run process before acknowledge
When it happens
Trigger: Calling acknowledge() either before any process() returned Completed, or a second time after the first acknowledge consumed pending_adjustments, or with outcomes for a batch that was never produced.
Common situations: Retry logic re-acknowledging the same batch; engine event ordering delivering acknowledge before the module's process completed; tests acknowledging with fabricated outcomes without running process first.
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
- cannot calculate CFD swap for {instrument_id}: midpoint over
- cannot calculate CFD swap for position {}: adjustment overfl
- cannot calculate CFD swap for position {}: currency conversi
- CFD swap rollover day is not initialized
- CFD swap acknowledgement count {}, expected {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/90346c8be45777b8.
Report an issue: GitHub.