nautechsystems/nautilus_trader · error

Cannot subscribe for synthetic instrument `InstrumentClose`

Error message

Cannot subscribe for synthetic instrument `InstrumentClose` data

What it means

InstrumentClose data comes from venues at session close and cannot be produced for locally generated synthetic instruments. The engine rejects SubscribeCommand::InstrumentClose for any synthetic instrument ID with this error.

Source

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

            }
            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,
            SubscribeCommand::BookDeltas(_) | SubscribeCommand::BookDepth10(_)
        );

        #[cfg(feature = "streaming")]
        let cmd = self.subscribe_command_with_prefilled_start_ns(cmd)?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip synthetic instrument IDs when subscribing to InstrumentClose data.
  2. Use the supported synthetic streams (e.g. Trades) for synthetic instruments.
  3. Restrict InstrumentClose subscriptions to real venue-listed instruments.

Example fix

// before
subscribe_all(engine, synthetic_id); // includes InstrumentClose
// after
if !synthetic_id.is_synthetic() {
    subscribe_all(engine, synthetic_id);
}
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

// Rust
match engine.subscribe_instrument_close(id) {
    Err(e) if e.to_string().contains("synthetic instrument `InstrumentClose`") => Ok(()),
    r => r,
}

Prevention

When it happens

Trigger: Subscribing to InstrumentClose with an InstrumentId where is_synthetic() is true, typically via a loop subscribing to every data type for every instrument.

Common situations: Wide-net subscription utilities that cover all data types; porting real-market subscription configs to synthetic instrument strategies.

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/20e7579e20f536f3. Report an issue: GitHub.