nautechsystems/nautilus_trader · error

Cannot add an `Instrument` object without first adding its a

Error message

Cannot add an `Instrument` object without first adding its associated venue {}

What it means

The backtest engine requires the venue for an instrument to be registered before the instrument itself is added. add_instrument checks that the instrument's venue exists in the kernel; if not, it aborts so market data routing has an exchange to attach to. This preserves the invariant that every instrument belongs to a known simulated venue.

Source

Thrown at crates/backtest/src/engine.rs:377

            exchange.borrow_mut().add_instrument(instrument.clone())?;
            if let Some(expiration_ns) = instrument.expiration_ns() {
                self.set_instrument_expiration_timer(exchange, instrument_id, expiration_ns)?;
            }

            if let Some(previous_expiration_ns) = previous_expiration_ns
                && instrument.expiration_ns() != Some(previous_expiration_ns)
                && !exchange
                    .borrow()
                    .has_unprocessed_instrument_expiration(previous_expiration_ns)
            {
                let timer_name = Self::instrument_expiration_timer_name(
                    instrument_id.venue,
                    previous_expiration_ns,
                );
                self.kernel.clock.borrow_mut().cancel_timer(&timer_name);
            }
        } else {
            anyhow::bail!(
                "Cannot add an `Instrument` object without first adding its associated venue {}",
                instrument.id().venue
            )
        }

        self.add_market_data_client_if_not_exists(instrument.id().venue);

        self.kernel
            .data_engine
            .borrow_mut()
            .process(instrument as &dyn Any);
        log::info!(
            "Added instrument {} to exchange {}",
            instrument_id,
            instrument_id.venue
        );
        Ok(())
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Call engine.add_venue(...) with a venue matching instrument.id().venue before add_instrument
  2. Verify instrument.id().venue string equals the venue passed to add_venue (case-sensitive exact match)
  3. Check that the instrument was built with the intended Venue, not a default or stale value

Example fix

// before
engine.add_instrument(instrument)?;
// after
engine.add_venue(venue, execution_engine_config, risk_engine_config)?;
engine.add_instrument(instrument)?;
Defensive patterns

Strategy: validation

Validate before calling

if !added_venues.contains(&instrument.id().venue) {
    anyhow::bail!("venue {} not added; call add_venue first", instrument.id().venue);
}
engine.add_instrument(instrument)?;

Try / catch

match engine.add_instrument(instrument) {
    Ok(()) => {},
    Err(e) if e.to_string().contains("without first adding its associated venue") => {
        eprintln!("add the venue before the instrument: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling engine.add_instrument(instrument) without a prior add_venue(...) for instrument.id().venue, or adding an instrument whose venue string does not exactly match the configured venue name.

Common situations: Copying an instrument from a live config whose venue name differs (e.g. 'BINANCE' vs 'BINANCE_FUTURES'); forgetting add_venue in a new script; instrument built for a venue that was never configured.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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