nautechsystems/nautilus_trader · error
Invalid generic spread leg component: {component}
Error message
Invalid generic spread leg component: {component} What it means
For generic spread symbols, `spread_contract_count` splits the symbol on the generic spread ID separator and parses each component into a leg ratio. This error fires when a component (e.g. a price or non-numeric segment) cannot be interpreted as a valid spread leg ratio.
Source
Thrown at crates/execution/src/models/fee.rs:355
let contracts = spread_contract_count(instrument)?;
let total = mul_checked(self.commission.as_decimal(), fill_quantity.as_decimal())
.and_then(|v| mul_checked(v, contracts))?;
Money::from_decimal(total, self.commission.currency).map_err(Into::into)
}
}
fn spread_contract_count(instrument: &InstrumentAny) -> anyhow::Result<Decimal> {
let instrument_id = instrument.id();
let symbol = instrument_id.symbol.as_str();
if !instrument.is_spread() || !symbol.contains(GENERIC_SPREAD_ID_SEPARATOR) {
return Ok(Decimal::ONE);
}
let mut total = 0_i64;
for component in symbol.split(GENERIC_SPREAD_ID_SEPARATOR) {
let ratio = spread_leg_ratio(component)
.ok_or_else(|| anyhow::anyhow!("Invalid generic spread leg component: {component}"))?;
total = total.checked_add(ratio).ok_or_else(|| {
anyhow::anyhow!("Generic spread contract count overflowed for {symbol}")
})?;
}
Ok(total.into())
}
fn spread_leg_ratio(component: &str) -> Option<i64> {
if let Some(rest) = component.strip_prefix("((") {
let (ratio, symbol) = rest.split_once("))")?;
return spread_leg_ratio_parts(ratio, symbol);
}
let rest = component.strip_prefix('(')?;
let (ratio, symbol) = rest.split_once(')')?;
spread_leg_ratio_parts(ratio, symbol)
}View on GitHub (pinned to 18893faf8b)
Solutions
- Check the symbol format: each separator-delimited component must encode a valid leg ratio.
- Build generic spread symbols only via the library's instrument/symbol factories rather than string concatenation.
- Print the failing component (included in the message) and correct that segment.
Example fix
// before let symbol = "ES-ES.N.202512-ES.H.202603"; // wrong components // after: use the canonical generic spread ID format with valid leg components let symbol = instrument_id.symbol.as_str(); // from a GenericSpreadInstrument
Defensive patterns
Strategy: validation
Validate before calling
components = symbol.split(GENERIC_SPREAD_ID_SEPARATOR)
assert all(spread_leg_ratio(c) is not None for c in components), f"bad component in {symbol}" Type guard
fn is_valid_spread_symbol(symbol: &str) -> bool {
symbol.split(GENERIC_SPREAD_ID_SEPARATOR).all(|c| spread_leg_ratio(c).is_some())
} Try / catch
let total = match spread_contract_count(symbol) {
Ok(n) => n,
Err(e) => { log::warn!("bad spread symbol {symbol}: {e}"); return; }
}; Prevention
- Construct generic spread symbols via library factories, not manual strings.
- Validate symbol format at instrument registration time.
- Note the failing component in the message when debugging format issues.
When it happens
Trigger: Calling `get_commission` on a generic spread instrument whose symbol contains a component that `spread_leg_ratio` cannot parse — malformed or non-standard generic spread symbol format.
Common situations: Constructing generic spread instrument IDs by hand with the wrong separator/format; symbols copied from another venue with different conventions; legacy symbol formats after a version change.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid Hyperliquid symbol format: {symbol}
- Generic spread contract count overflowed for {symbol}
- Invalid scientific notation exponent '{exponent}': must be a
- {FAILED}: {e}
- {FAILED}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/bfe29e25511aadf9.
Report an issue: GitHub.