nautechsystems/nautilus_trader · error · anyhow::Error
Cannot cache futures spread: missing option price for {call_
Error message
Cannot cache futures spread: missing option price for {call_instrument_id} What it means
After fetching the reference futures price, `cache_futures_spread` fetches the CALL option's price via `get_price`. If no price is cached for the call instrument the spread cannot be computed and it bails with this error.
Source
Thrown at crates/common/src/greeks.rs:1122
if call_instrument.strike_price() != put_instrument.strike_price() {
anyhow::bail!(
"Cannot cache futures spread: strike prices differ call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
);
}
if call_instrument.expiration_ns() != put_instrument.expiration_ns() {
anyhow::bail!(
"Cannot cache futures spread: expiration dates differ call_instrument_id={call_instrument_id} put_instrument_id={put_instrument_id}"
);
}
let reference_future_price = self.get_price_object(&futures_instrument_id).ok_or_else(|| {
anyhow::anyhow!(
"Cannot cache futures spread: no reference futures price for {futures_instrument_id}"
)
})?;
let call_price = self.get_price(&call_instrument_id).ok_or_else(|| {
anyhow::anyhow!(
"Cannot cache futures spread: missing option price for {call_instrument_id}"
)
})?;
let put_price = self.get_price(&put_instrument_id).ok_or_else(|| {
anyhow::anyhow!(
"Cannot cache futures spread: missing option price for {put_instrument_id}"
)
})?;
let underlying_instrument_id =
InstrumentId::from(format!("{call_underlying}.{}", call_instrument_id.venue));
// Reject if the underlying is present in cache but is not a future
{
let cache = self.cache.borrow();
if let Some(underlying) = cache.instrument(&underlying_instrument_id)
&& underlying.instrument_class() != InstrumentClass::Future
{View on GitHub (pinned to 18893faf8b)
Solutions
- Subscribe to quotes/trades for the call instrument and confirm a price exists before caching the spread.
- Verify call/put instrument IDs are not swapped and match the same expiration.
- Pick a strike with active market data, or retry after the first quote tick.
- Handle the error at call sites and skip the synthetic-price caching for strikes without data.
Example fix
// before
engine.cache_futures_spread(&fut_id, &call_id, &put_id, &underlying)?;
// after
if engine.cache.price(&call_id).is_none() {
return Ok(()); // skip strikes without market data
}
engine.cache_futures_spread(&fut_id, &call_id, &put_id, &underlying)?; Defensive patterns
Strategy: fallback
Validate before calling
// Rust: check call leg before computing the spread
if cache.price(&call_instrument_id).is_none() {
return Ok(()); // skip strikes without call quotes
} Type guard
fn price_or_skip(cache: &Cache, id: &InstrumentId) -> Option<f64> { cache.price(id) } Try / catch
match engine.cache_futures_spread(&fut_id, &call_id, &put_id, &u) {
Err(e) if e.to_string().contains(&call_id.to_string()) => debug!("no call price {call_id}"),
other => other?,
} Prevention
- Subscribe to quotes for every strike you intend to use.
- Filter strikes to those with live two-sided quotes before spread caching.
- Validate call/put IDs come from the same expiry to avoid leg mismatches.
- Retry after the next quote tick; first-tick races are common.
When it happens
Trigger: cache_futures_spread called when the call option instrument has no quote/trade price in the cache (options not subscribed, illiquid strike with no market, wrong call instrument ID, or call expired).
Common situations: Deep OTM/ITM strikes with no quotes; subscribing to a subset of the chain; passing swapped call/put IDs; running during the first milliseconds after subscription before quotes arrive.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Cannot cache futures spread: missing option price for {put_i
- Cannot cache futures spread: no reference futures price for
- option_summary_family_subs mutex poisoned
- DataActor {} must be registered before calling `cache()` - t
- Order {client_order_id} not found
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2e00c0f10f86b7f7.
Report an issue: GitHub.