nautechsystems/nautilus_trader · error · anyhow::Error
Cannot cache futures spread: non-option instruments provided
Error message
Cannot cache futures spread: non-option instruments provided call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id} What it means
cache_futures_spread validates that both provided instruments are of InstrumentClass::Option after resolving them from the Cache. If either the call or put argument resolves to a non-option instrument (e.g. a future, spot, or spread instrument), it bails with this error. The method only computes an implied-future spread from an option pair, so any other class is rejected up front.
Source
Thrown at crates/common/src/greeks.rs:1074
anyhow::bail!(
"Cannot cache futures spread: missing option instrument {call_instrument_id}"
);
};
let Some(put_instrument) = put_instrument else {
anyhow::bail!(
"Cannot cache futures spread: missing option instrument {put_instrument_id}"
);
};
let Some(reference_future_instrument) = reference_future_instrument else {
anyhow::bail!(
"Cannot cache futures spread: no reference futures instrument for {futures_instrument_id}"
);
};
if call_instrument.instrument_class() != InstrumentClass::Option
|| put_instrument.instrument_class() != InstrumentClass::Option
{
anyhow::bail!(
"Cannot cache futures spread: non-option instruments provided call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
);
}
if call_instrument.option_kind() != Some(OptionKind::Call)
|| put_instrument.option_kind() != Some(OptionKind::Put)
{
anyhow::bail!(
"Cannot cache futures spread: expected call/put pair call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
);
}
let Some(call_underlying) = call_instrument.underlying() else {
anyhow::bail!(
"Cannot cache futures spread: missing call underlying for {call_instrument_id}"
);
};
let Some(put_underlying) = put_instrument.underlying() else {View on GitHub (pinned to 18893faf8b)
Solutions
- Check instrument_class() == InstrumentClass::Option for both IDs before calling cache_futures_spread.
- Verify argument order: call_instrument_id and put_instrument_id must both be options; the future goes in the third parameter.
- Inspect the cached instrument for the offending ID to confirm its actual class and correct the ID source.
Example fix
// before let price = greeks.cache_futures_spread(future_id, put_id, future_id)?; // after assert_eq!(cache.instrument(&call_id).unwrap().instrument_class(), InstrumentClass::Option); assert_eq!(cache.instrument(&put_id).unwrap().instrument_class(), InstrumentClass::Option); let price = greeks.cache_futures_spread(call_id, put_id, future_id)?;
Defensive patterns
Strategy: validation
Validate before calling
// rust
fn is_option_pair(cache: &Cache, call_id: &InstrumentId, put_id: &InstrumentId) -> bool {
matches!(
(cache.instrument(call_id), cache.instrument(put_id)),
(Some(c), Some(p)) if c.instrument_class() == InstrumentClass::Option && p.instrument_class() == InstrumentClass::Option
)
} Type guard
fn as_option(cache: &Cache, id: &InstrumentId) -> Option<&InstrumentAny> {
cache.instrument(id).filter(|i| i.instrument_class() == InstrumentClass::Option)
} Try / catch
let res = greeks.cache_futures_spread(call_id, put_id, future_id);
if let Err(e) = &res {
if e.to_string().contains("non-option instruments") {
tracing::warn!("bad pair {call_id}/{put_id}: {e}");
}
} Prevention
- Keep option IDs and futures IDs in separate typed collections so they cannot be passed in the wrong slots.
- Assert instrument classes once when loading instruments into cache, not per call.
- Never reuse a single ID variable for both the option legs and the reference future.
When it happens
Trigger: Passing a futures or cash instrument ID in either call_instrument_id or put_instrument_id; swapping arguments so a future lands in the call slot; a cached instrument whose class differs from what the caller assumed (e.g. a generic 'spread' or 'continued' contract).
Common situations: Building IDs programmatically from a symbol table where option and future IDs share a prefix; feeding the reference future ID into the call/put slots by mistake; vendor data classifying an instrument differently than expected.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot cache futures spread: expected call/put pair call_ins
- Cannot cache futures spread: option underlyings differ call_
- Cannot cache futures spread: strike prices differ call_instr
- Cannot cache futures spread: expiration dates differ call_in
- option_summary_family_subs mutex poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ab2d3b02418b391c.
Report an issue: GitHub.