nautechsystems/nautilus_trader · error

next index is within the data batch

Error message

next index is within the data batch

What it means

During heap replay in the backtest DataIterator, an entry's cursor is advanced to next_index and the corresponding item is fetched from the stream batch before being pushed back onto the heap. The code asserts with expect() that next_index is in bounds because the caller only advances when next_index < stream.len(). Violation indicates an internal cursor/heap bookkeeping bug, not bad user input.

Source

Thrown at crates/backtest/src/data_iterator.rs:309

        // Multi-stream path using heap
        let Some(entry) = self.heap.pop() else {
            return;
        };

        let Some(stream) = self.streams.get(&entry.priority) else {
            return;
        };

        // Advance cursor and push next entry
        let next_index = entry.index + 1;
        self.indices.insert(entry.priority, next_index);

        if next_index < stream.len() {
            self.heap.push(HeapEntry {
                key: replay_key(
                    stream
                        .get(next_index)
                        .expect("next index is within the data batch"),
                ),
                priority: entry.priority,
                index: next_index,
            });
        }
    }

    /// Returns the next backtest data element across all streams in replay order.
    pub(crate) fn next_item(&mut self) -> Option<Data> {
        let element = if let Some(p) = self.single_priority {
            let data = self.streams.get(&p)?;
            let idx = *self.indices.get(&p)?;
            data.get_owned(idx)?
        } else {
            let entry = self.heap.peek()?;
            self.streams.get(&entry.priority)?.get_owned(entry.index)?
        };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify no custom code mutates the underlying data batch while iterating
  2. Reproduce with a minimal dataset and report the bug to NautilusTrader maintainers with the repro
  3. Pin/upgrade to a version where the data_iterator heap bug is fixed
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard custom data batches passed to the backtest iterator:
assert!(stream.iter().all(|d| !is_stale(d)), "stream contains stale entries");

Type guard

fn in_bounds(idx: usize, stream_len: usize) -> bool { idx < stream_len }

Try / catch

// Panic is not catchable in normal Rust; verify with a custom Clock/TestClock harness
// and report a repro to maintainers if hit.

Prevention

When it happens

Trigger: Only reachable via a defect in DataIterator's heap replay logic where an entry is re-pushed with next_index >= stream.len() (stale index, double-advance, or mutated stream). Normal API use (iterating the backtest data stream) cannot trigger it.

Common situations: Encountered only after upgrading NautilusTrader versions where iterator internals changed, or when a custom data stream implementation mutates during iteration. End users should never see this.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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