nautechsystems/nautilus_trader · error

Slice length != 10

Error message

Slice length != 10

What it means

orderbook_depth10_new builds fixed-size [BookOrderFfi; 10] arrays from raw pointers by converting a slice of DEPTH10_LEN via try_into().expect("Slice length != 10"). Although the slice is created with from_raw_parts(..., DEPTH10_LEN) and therefore should always be length 10, if the conversion is invoked with a differently sized buffer/layout mismatch this expect panics. It is an internal invariant check guarding the fixed-depth-10 FFI contract.

Source

Thrown at crates/model/src/ffi/data/depth.rs:108

    asks_ptr: *const BookOrderFfi,
    bid_counts_ptr: *const u32,
    ask_counts_ptr: *const u32,
    flags: u8,
    sequence: u64,
    ts_event: UnixNanos,
    ts_init: UnixNanos,
) -> OrderBookDepth10Ffi {
    abort_on_panic(|| {
        // SAFETY: Null checks run before slice construction. The caller still
        // guarantees each pointer refers to `DEPTH10_LEN` initialized elements.
        assert!(!bids_ptr.is_null());
        assert!(!asks_ptr.is_null());
        assert!(!bid_counts_ptr.is_null());
        assert!(!ask_counts_ptr.is_null());

        let bids_slice = unsafe { std::slice::from_raw_parts(bids_ptr, DEPTH10_LEN) };
        let asks_slice = unsafe { std::slice::from_raw_parts(asks_ptr, DEPTH10_LEN) };
        let bids: [BookOrderFfi; DEPTH10_LEN] = bids_slice.try_into().expect("Slice length != 10");
        let asks: [BookOrderFfi; DEPTH10_LEN] = asks_slice.try_into().expect("Slice length != 10");

        let bid_counts_slice = unsafe { std::slice::from_raw_parts(bid_counts_ptr, DEPTH10_LEN) };
        let ask_counts_slice = unsafe { std::slice::from_raw_parts(ask_counts_ptr, DEPTH10_LEN) };
        let bid_counts: [u32; DEPTH10_LEN] =
            bid_counts_slice.try_into().expect("Slice length != 10");
        let ask_counts: [u32; DEPTH10_LEN] =
            ask_counts_slice.try_into().expect("Slice length != 10");

        OrderBookDepth10::new(
            instrument_id,
            bids.map(Into::into),
            asks.map(Into::into),
            bid_counts,
            ask_counts,
            flags,
            sequence,
            ts_event,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Allocate exactly 10 elements of the exact BookOrderFfi layout for bids and asks before the call.
  2. Rebuild bindings against the current model crate so BookOrderFfi size/alignment match on both sides.
  3. Check for compiler warnings about type layout changes after upgrading nautilus; pin compatible versions.
  4. If you maintain the FFI wrapper, assert the ctypes.sizeof/length equals the Rust-side size and 10 elements before calling.

Example fix

// before (ctypes)
bids = (BookOrderFfi * depth) (*orders)  # depth may not be 10
// after
assert depth == 10, "Depth10 requires exactly 10 orders per side"
bids = (BookOrderFfi * 10)(*orders[:10])
Defensive patterns

Strategy: validation

Validate before calling

# Python caller
assert len(bids) == 10 and len(asks) == 10, "Depth10 needs exactly 10 orders per side"

Prevention

When it happens

Trigger: Calling orderbook_depth10_new with bid/ask pointer buffers that are not exactly 10 contiguous BookOrderFfi elements (undersized allocations, wrong struct packing, or mismatched layout between caller and library).

Common situations: Custom Cython/ctypes bindings that allocate arrays with the wrong element size or count, ABI drift after BookOrderFfi changed, or adapter code reusing depth buffers sized for other depth levels.

Related errors


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