nautechsystems/nautilus_trader · error

Cannot expand parent subscription for {instrument_id}: symbo

Error message

Cannot expand parent subscription for {instrument_id}: symbol does not parse as `<root>.<class>` with a recognized class suffix

What it means

Parent subscriptions (subscribing to all contracts of a root, e.g. 'ES.NYMEX' as a parent) are expressed as symbol strings of the form '<root>.<class>' where class is a recognized InstrumentClass suffix. When expanding such a subscription, the engine could not split the instrument ID into root and class components, meaning the symbol is malformed or uses an unrecognized suffix.

Source

Thrown at crates/data/src/engine/mod.rs:5625

    }
}

// Resolves parent expansion components for a book subscription command.
//
// Returns Ok(Some((root, class))) when params carries PARAMS_IS_PARENT=true and
// the instrument_id parses as a recognized <root>.<class> shape; Ok(None) for
// concrete (non-parent) subscriptions; Err when the caller asserts a parent
// subscription but the id cannot be parsed, so subscribe entries can reject up
// front before touching state.
fn resolve_parent_components(
    instrument_id: &InstrumentId,
    params: Option<&Params>,
) -> anyhow::Result<Option<(Ustr, InstrumentClass)>> {
    if !is_parent_subscription(params) {
        return Ok(None);
    }
    let Some((root, class)) = instrument_id.parse_parent_components() else {
        anyhow::bail!(
            "Cannot expand parent subscription for {instrument_id}: \
             symbol does not parse as `<root>.<class>` with a recognized class suffix"
        );
    };
    Ok(Some((Ustr::from(root), class)))
}

fn register_external_streaming_type(cmd: &SubscribeCommand) {
    if let Some(payload_type) = streaming_payload_type(cmd) {
        msgbus::get_message_bus()
            .borrow_mut()
            .add_streaming_type(payload_type);
    }
}

fn publish_external_data_command<T>(client_id: ClientId, command: &T)
where
    T: Any,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use the correct parent format '<root>.<class>', e.g. 'ES.FUTURE' (with a recognized InstrumentClass suffix).
  2. Check parse_parent_components / InstrumentClass for the list of recognized suffixes and match one exactly.
  3. If you want a specific contract, don't set the parent-subscription params; subscribe to the full instrument ID directly.

Example fix

// before
engine.subscribe(InstrumentId::from("ESX"), Some(parent_params))?;
// after
engine.subscribe(InstrumentId::from("ES.FUTURE"), Some(parent_params))?;
Defensive patterns

Strategy: validation

Validate before calling

if is_parent_subscription(params) && instrument_id.parse_parent_components().is_none() {
    anyhow::bail!("{} is not a valid parent symbol <root>.<class>", instrument_id);
}

Type guard

fn is_valid_parent_symbol(id: &InstrumentId) -> bool {
    id.parse_parent_components().is_some()
}

Try / catch

match expand_parent_subscription(&instrument_id, params) {
    Err(e) if e.to_string().contains("does not parse as `<root>.<class>`") => {
        eprintln!("use e.g. ES.FUTURE for parent subscriptions");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Passing params that mark a subscription as a parent subscription (is_parent_subscription) together with an instrument_id whose symbol does not match '<root>.<class>' — missing the dot, or using an unknown class suffix (not FUTURE, OPTION, etc.).

Common situations: Typos in the parent symbol ('ESX' instead of 'ES.FUTURE'); inventing custom class suffixes the parser doesn't recognize; using a full contract ID like 'ESH6.XCME' where a parent root is expected.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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