nautechsystems/nautilus_trader · error

Catalog {catalog_name} disappeared between timestamp query a

Error message

Catalog {catalog_name} disappeared between timestamp query and read

What it means

dispatch_instrument_request resolves a catalog by name after computing the timestamp bounds for an instrument query; if the named catalog is no longer registered in self.catalogs, the engine raises this error. It guards against serving instrument data from an unexpected or half-torn-down catalog.

Source

Thrown at crates/data/src/engine/streaming.rs:556

        let identifier = cmd.instrument_id.to_string();
        let Some(catalog_name) = self.catalog_with_last_timestamp("instruments", &identifier)?
        else {
            return self
                .dispatch_request_to_client(RequestCommand::Instrument(cmd))
                .map(|_| ());
        };

        let now_ns = self.clock.borrow().timestamp_ns();
        let used_client_id = self
            .get_client(cmd.client_id.as_ref(), Some(&cmd.instrument_id.venue))
            .map(|client| client.client_id());
        let (start_dt, end_dt) =
            bound_request_dates(cmd.start, cmd.end, now_ns.to_datetime_utc(), true);
        let start_ns = datetime_to_unix_nanos_or_zero(start_dt);
        let end_ns = datetime_to_unix_nanos_or_zero(end_dt);
        let query_end = cmd.end.map(datetime_to_unix_nanos_or_zero);
        let catalog = self.catalogs.get(&catalog_name).ok_or_else(|| {
            anyhow::anyhow!("Catalog {catalog_name} disappeared between timestamp query and read")
        })?;
        let mut data = catalog.instruments(
            Some(std::slice::from_ref(&identifier)),
            Some(start_ns),
            query_end,
        )?;
        data = latest_instruments(data);

        if let Some(instrument) = data.into_iter().next() {
            let response = DataResponse::Instrument(Box::new(InstrumentResponse::new(
                cmd.request_id,
                resolve_response_client_id(cmd.client_id, used_client_id),
                cmd.instrument_id,
                instrument,
                Some(start_ns),
                Some(end_ns),
                now_ns,
                Some(catalog_response_params(cmd.params.as_ref())),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the catalog_name in the instrument request matches a registered catalog exactly.
  2. Re-register the catalog before dispatching instrument requests.
  3. Avoid deregistering/closing catalogs while instrument requests may be in flight.
  4. Validate the catalog exists once at request intake and fail fast with a clear message before doing timestamp work.
Defensive patterns

Strategy: validation

Validate before calling

// resolve the catalog once before computing bounds / dispatching
let catalog = engine.catalogs.get(&catalog_name)
    .ok_or_else(|| anyhow::anyhow!("catalog {catalog_name} not registered"))?;

Prevention

When it happens

Trigger: Calling dispatch_instrument_request (via dispatch_instrument_catalog_request) when self.catalogs.get(&catalog_name) returns None — the catalog was never registered under that exact name or was removed between the earlier timestamp query and the read.

Common situations: Instrument catalog request issued with a misspelled or renamed catalog; catalog deregistered concurrently by another actor; request replayed after engine shutdown cleared registered catalogs.

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