nautechsystems/nautilus_trader · error · anyhow::Error
Resolved BAG spread {spread_instrument_id} is not cached
Error message
Resolved BAG spread {spread_instrument_id} is not cached What it means
After deriving a spread instrument ID from a BAG contract's combo legs, the adapter requires that the resulting spread instrument already exist in the provider's instrument cache. If the legs resolved to a valid spread ID but no cached instrument matches it, this error prevents returning an ID for an instrument the system has no definition for.
Source
Thrown at crates/adapters/interactive_brokers/src/providers/instruments.rs:541
.with_context(|| {
format!(
"Cannot resolve BAG leg con_id {} to cached instrument ID",
combo_leg.contract_id
)
})?;
let ratio = IbAction::from_str(combo_leg.action.as_str())
.context("Invalid BAG combo leg action")?
.signed_multiplier()
* combo_leg.ratio;
leg_tuples.push((leg_instrument_id, ratio));
}
let spread_instrument_id = create_spread_instrument_id(&leg_tuples)
.context("Failed to create spread instrument ID from BAG combo legs")?;
if self.find(&spread_instrument_id).is_none() {
anyhow::bail!("Resolved BAG spread {spread_instrument_id} is not cached");
}
Ok(spread_instrument_id)
}
/// Check if a security type should be filtered.
///
/// # Arguments
///
/// * `sec_type` - The security type to check
///
/// # Returns
///
/// Returns `true` if the security type should be filtered.
#[must_use]
pub fn is_filtered_sec_type(&self, sec_type: &str) -> bool {
self.config
.filter_sec_typesView on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the spread instrument was created/cached first — call get_instrument (or the loader) for the spread before resolving its ID.
- Check that the leg instruments composing the spread are themselves loaded and unchanged (leg changes alter the computed spread ID).
- Re-run instrument loading after adapter restarts so the cache is repopulated.
- If the spread is new, define it explicitly so its ID matches the combination of leg IDs and ratios.
Example fix
// before: resolving before the spread is defined let id = provider.resolve_instrument_id_for_contract(&bag)?; // after: define/load the spread first, then resolve let instrument = provider.get_instrument(&client, &bag)?; // caches spread definition let id = instrument.id();
Defensive patterns
Strategy: validation
Validate before calling
fn spread_is_cached(provider: &IbInstrumentsProvider, id: &InstrumentId) -> bool {
provider.find(id).is_some()
} Prevention
- Load the spread definition via get_instrument before resolving its ID
- Repopulate the instrument cache after adapter restarts
- Keep leg instruments stable — changing legs changes the spread ID
When it happens
Trigger: resolve_spread_instrument_id_for_contract computes create_spread_instrument_id from the legs, but find(&spread_instrument_id) returns None — i.e., the spread was never loaded/defined via get_instrument or load path beforehand.
Common situations: Requesting a spread whose leg instruments were never subscribed/loaded, legs changed so the computed ID no longer matches any cached definition, or the spread definition was created after the resolution attempt.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Cannot resolve BAG contract without combo legs or cached con
- Invalid BAG contract: must have security_type=Spread and non
- No valid legs loaded for BAG contract
- Leg instrument {} not found in contract details after loadin
- Contract details not found for leg {} after loading
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cedb402f10b5cf02.
Report an issue: GitHub.