nautechsystems/nautilus_trader · error

Cannot unsubscribe from synthetic instrument `OptionGreeks`

Error message

Cannot unsubscribe from synthetic instrument `OptionGreeks` data

What it means

The DataEngine rejects unsubscribing from OptionGreeks data for a synthetic instrument ID. OptionGreeks streams for synthetic instruments are computed locally, so no downstream client subscription exists and the unsubscribe command is invalid.

Source

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

            UnsubscribeCommand::Trades(cmd) if cmd.instrument_id.is_synthetic() => {
                self.unsubscribe_synthetic_trades(cmd.instrument_id);
                return Ok(());
            }
            UnsubscribeCommand::Instrument(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!("Cannot unsubscribe from synthetic instrument `Instrument` data");
            }
            UnsubscribeCommand::InstrumentStatus(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!(
                    "Cannot unsubscribe from synthetic instrument `InstrumentStatus` data"
                );
            }
            UnsubscribeCommand::InstrumentClose(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!(
                    "Cannot unsubscribe from synthetic instrument `InstrumentClose` data"
                );
            }
            UnsubscribeCommand::OptionGreeks(cmd) if cmd.instrument_id.is_synthetic() => {
                anyhow::bail!("Cannot unsubscribe from synthetic instrument `OptionGreeks` data");
            }
            _ => {}
        }

        if let Some(client) = self.get_command_client(cmd.client_id(), cmd.venue()) {
            client.execute_unsubscribe(cmd);
        } else {
            log::error!(
                "Cannot handle command: no client found for client_id={:?}, venue={:?}",
                cmd.client_id(),
                cmd.venue(),
            );
        }

        Ok(())
    }

    /// Sends a [`RequestCommand`] to a suitable data client implementation.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip the unsubscribe call for synthetic instrument IDs (synthetic greeks are engine-computed)
  2. Check instrument_id.is_synthetic() before constructing the OptionGreeks unsubscribe command
  3. Use a real exchange-listed option instrument ID when unsubscribing from venue greeks data
  4. Manage synthetic greeks lifecycle through the SyntheticInstrument API instead

Example fix

// before
for id in active_ids {
    engine.unsubscribe(OptionGreeks::new(id, client_id, venue));
}
// after
for id in active_ids.into_iter().filter(|id| !id.is_synthetic()) {
    engine.unsubscribe(OptionGreeks::new(id, client_id, venue));
}
Defensive patterns

Strategy: validation

Validate before calling

if instrument_id.is_synthetic() {
    return Ok(()); // synthetic greeks lifecycle is engine-managed
}

Type guard

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

Try / catch

if let Err(e) = engine.unsubscribe(cmd) {
    if e.to_string().contains("synthetic") { log::debug!("ignoring: {e}"); }
    else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling DataEngine.unsubscribe with UnsubscribeCommand::OptionGreeks where cmd.instrument_id.is_synthetic() is true — i.e. an ID minted by SyntheticInstrument rather than a venue-listed option ID.

Common situations: Passing a synthetic option ID built from a synthetic underlying into greeks subscription management; generic unsubscribe loops that iterate all active subscriptions including synthetic ones.

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