nautechsystems/nautilus_trader · error

`deltas` instrument IDs must match `instrument_id` {instrume

Error message

`deltas` instrument IDs must match `instrument_id` {instrument_id}, but delta at index {index} of {} has {}

What it means

`timedelta`'s Year arm proxies a year as 365 days: `step.checked_mul(365)`. The `.expect("`step` overflows i64 days")` panics when step * 365 exceeds i64::MAX. This mirrors the Month/Week proxy calculations and guards the duration conversion.

Source

Thrown at crates/model/src/data/deltas.rs:105

        instrument_id: InstrumentId,
        deltas: Vec<OrderBookDelta>,
    ) -> anyhow::Result<Self> {
        check_predicate_true(!deltas.is_empty(), "`deltas` cannot be empty")?;

        let mismatch = deltas.iter().enumerate().find(|(_, delta)| {
            instrument_id != delta.instrument_id
                && (instrument_id.symbol.as_str() != delta.instrument_id.symbol.as_str()
                    || instrument_id.venue.as_str() != delta.instrument_id.venue.as_str())
        });

        if let Some((index, delta)) = mismatch {
            check_predicate_true(
                false,
                &format!(
                    "`deltas` instrument IDs must match `instrument_id` {instrument_id}, but \
                     delta at index {index} of {} has {}",
                    deltas.len(),
                    delta.instrument_id,
                ),
            )?;
        }
        let last = deltas.last().expect("deltas not empty");
        let flags = last.flags;
        let sequence = last.sequence;
        let ts_event = last.ts_event;
        let ts_init = last.ts_init;
        Ok(Self {
            instrument_id,
            deltas,
            flags,
            sequence,
            ts_event,
            ts_init,
        })
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Validate year step values are realistic before constructing the BarType
  2. Audit where the step value is produced for unit mistakes
  3. Re-validate BarType specs after deserialization

Example fix

// before
let td = bar_type.timedelta();
// after
assert!(bar_type.aggregation() != BarAggregation::Year || bar_type.step().get() < 25_000_000_000_000_000, "year step too large");
let td = bar_type.timedelta();
Defensive patterns

Strategy: validation

Validate before calling

def validate_year_step(step: int) -> int:
    if step >= 25_268_416_409_306:  # i64::MAX // 365 (approx)
        raise ValueError(f"year step {step} overflows i64 days")
    return step

Try / catch

try:
    td = bar_type.timedelta
except Exception as e:
    logger.error(f"year step overflow: {e}")
    raise

Prevention

When it happens

Trigger: Calling `timedelta` (via `bar_close_from_open`, `py_timedelta`, `py_get_interval_ns`) on a BarType with Year aggregation and step > i64::MAX / 365 (about 25 quadrillion years).

Common situations: Unit-conversion bugs when building the BarType step; corrupted or malicious deserialized specs; generated aggregation specs with runaway multipliers.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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