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
- Verify the catalog_name in the instrument request matches a registered catalog exactly.
- Re-register the catalog before dispatching instrument requests.
- Avoid deregistering/closing catalogs while instrument requests may be in flight.
- 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
- Validate catalog_name against registered catalogs at request intake.
- Avoid renaming or removing catalogs while instrument requests may be pending.
- Use a single source of truth for catalog names (constants/config) instead of string literals.
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
- Catalog {catalog_name} disappeared between intervals query a
- instrument update lock poisoned
- heartbeat_secs must be positive when set
- missing persistence type for order update {}
- Binance v2 does not support instrument filter_callable {filt
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/671a031ae9a7174e.
Report an issue: GitHub.