nautechsystems/nautilus_trader · error

Cannot subscribe for synthetic instrument `Instrument` data

Error message

Cannot subscribe for synthetic instrument `Instrument` data

What it means

Synthetic instrument IDs support generated Trades (and some other streams) but not `Instrument` definition subscriptions. When a SubscribeCommand for Instrument data targets a synthetic instrument ID, the engine immediately rejects it since there is no real venue to provide instrument definitions for a synthetic instrument.

Source

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

                self.subscribe_option_chain(cmd);
                return Ok(());
            }
            SubscribeCommand::Quotes(cmd) if cmd.instrument_id.is_synthetic() => {
                self.subscribe_synthetic_quotes(cmd.instrument_id);
                return Ok(());
            }
            SubscribeCommand::Quotes(cmd)
                if self.is_spread_quote_command(cmd.instrument_id, cmd.params.as_ref()) =>
            {
                self.subscribe_spread_quotes(cmd);
                return Ok(());
            }
            SubscribeCommand::Trades(cmd) if cmd.instrument_id.is_synthetic() => {
                self.subscribe_synthetic_trades(cmd.instrument_id);
                return Ok(());
            }
            SubscribeCommand::Instrument(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!("Cannot subscribe for synthetic instrument `Instrument` data");
            }
            SubscribeCommand::InstrumentStatus(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!("Cannot subscribe for synthetic instrument `InstrumentStatus` data");
            }
            SubscribeCommand::InstrumentClose(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!("Cannot subscribe for synthetic instrument `InstrumentClose` data");
            }
            SubscribeCommand::OptionGreeks(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!("Cannot subscribe for synthetic instrument `OptionGreeks` data");
            }
            _ => {} // Do nothing else
        }

        let retained = cmd.clone();

        // Book ownership, including failed acquisitions, is already counted by the engine
        let retain_on_failure = !matches!(
            &cmd,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Do not subscribe to `Instrument` data for synthetic instrument IDs; instead subscribe to synthetic Trades or the stream types the engine supports for synthetics.
  2. Filter synthetic instrument IDs out of the subscription list before issuing Instrument subscribe commands.
  3. If instrument definitions are needed, register/define the synthetic instrument directly rather than via a data subscription.

Example fix

// before
for id in instrument_ids {
    engine.subscribe_instruments(id)?; // fails for synthetic ids
}
// after
for id in instrument_ids.iter().filter(|id| !id.is_synthetic()) {
    engine.subscribe_instruments(*id)?;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Rust
fn can_subscribe_instrument(id: InstrumentId) -> bool { !id.is_synthetic() }

Type guard

// Rust
fn is_real_instrument(id: &InstrumentId) -> bool {
    !id.is_synthetic()
}

Try / catch

// Rust
match engine.subscribe_instruments(id) {
    Err(e) if e.to_string().contains("synthetic instrument `Instrument`") => {
        log::warn!("skipping Instrument subscription for synthetic {id}");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling subscribe (SubscribeCommand::Instrument) with an InstrumentId that is synthetic (is_synthetic() true, e.g. an ID with the synthetic venue) instead of subscribing to synthetic trades or using a real instrument ID.

Common situations: Code that generically subscribes to Instrument data for all instruments in a portfolio, accidentally including synthetic instruments; migrating strategies from real to synthetic instruments without changing subscription types.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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