nautechsystems/nautilus_trader · error

instrument ID `{instrument_id}` is not for venue {}

Error message

instrument ID `{instrument_id}` is not for venue {}

What it means

Derive adapter's currency_from_instrument_id helper only accepts instrument IDs belonging to the Derive venue. If the caller passes an instrument ID minted for a different venue (or with a malformed venue portion), the ensure! macro aborts with this message naming the offending ID and the expected venue. It is a guard against silently deriving a currency from a non-Derive instrument.

Source

Thrown at crates/adapters/derive/src/data.rs:2397

fn trade_channel(instrument: &InstrumentAny) -> anyhow::Result<String> {
    let instrument_type = derive_instrument_type(instrument)?.to_string();
    let instrument_id = instrument.id();
    let currency = currency_from_instrument_id(&instrument_id)?;
    Ok(trades_channel(&instrument_type, currency))
}

fn derive_instrument_type(instrument: &InstrumentAny) -> anyhow::Result<DeriveInstrumentType> {
    match instrument {
        InstrumentAny::CryptoPerpetual(_) => Ok(DeriveInstrumentType::Perp),
        InstrumentAny::CryptoOption(_) => Ok(DeriveInstrumentType::Option),
        InstrumentAny::CurrencyPair(_) => Ok(DeriveInstrumentType::Erc20),
        other => anyhow::bail!("unsupported Derive instrument type for trades: {other:?}"),
    }
}

fn currency_from_instrument_id(instrument_id: &InstrumentId) -> anyhow::Result<&str> {
    anyhow::ensure!(
        instrument_id.venue == *DERIVE_VENUE,
        "instrument ID `{instrument_id}` is not for venue {}",
        DERIVE_VENUE.as_str(),
    );

    instrument_id
        .symbol
        .as_str()
        .split_once('-')
        .and_then(|(currency, _)| (!currency.is_empty()).then_some(currency))
        .ok_or_else(|| anyhow::anyhow!("cannot derive currency from {instrument_id}"))
}

// Caps the rendered JSON at ~512 bytes for log grep-ability and backs the
// slice off to a UTF-8 char boundary so a multi-byte codepoint near the cap
// can never produce a panicking slice.
fn truncated_payload_snippet(raw: &str) -> String {
    const MAX_LEN: usize = 512;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the InstrumentId passed to Derive calls was created for the Derive venue (use the adapter's DERIVE_VENUE constant or its instrument-ID parsing helper).
  2. Verify the venue portion of the ID string matches Derive exactly (case/format as defined by DERIVE_VENUE).
  3. If handling multiple venues, filter or dispatch instrument IDs by venue before reaching the Derive client.
  4. Log the full instrument ID and expected venue to find where the cross-venue ID leaked in.

Example fix

// before
let id = InstrumentId::from("ETH-PERP.BINANCE");
derive_client.currency_from_instrument_id(&id)?;
// after
let id = InstrumentId::from("ETH-PERP.DERIVE");
derive_client.currency_from_instrument_id(&id)?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_derive_instrument(id: &InstrumentId) -> Result<(), String> {
    if id.venue.as_str() != DERIVE_VENUE.as_str() {
        return Err(format!("{} is not a Derive instrument (venue {})", id, id.venue));
    }
    Ok(())
}

Type guard

fn is_derive_instrument(id: &InstrumentId) -> bool {
    id.venue == *DERIVE_VENUE
}

Try / catch

match derive_client.currency_from_instrument_id(&id) {
    Ok(cur) => /* use currency */,
    Err(e) => log::warn!("skip non-Derive instrument: {e}"),
}

Prevention

When it happens

Trigger: Calling Derive data/execution code paths that resolve a currency (e.g. to build request parameters) with an InstrumentId whose venue != Derive, such as passing a Binance instrument ID into a Derive API call, or constructing an InstrumentId manually with a typo'd venue string.

Common situations: Routing logic that forwards instrument IDs from a multi-venue portfolio into Derive-specific helpers; copy-pasted instrument IDs in config or test fixtures; venue string casing mistakes when parsing user input.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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