nautechsystems/nautilus_trader · error
Instrument close not found in Redis: {key}
Error message
Instrument close not found in Redis: {key} What it means
load_instrument_closes reads a bulk set of keys from Redis and zips keys with values. If Redis returns None (nil) for a key that the instrument-close index listed — the key existed in the index but the value is missing — this error is thrown naming the missing key.
Source
Thrown at crates/infrastructure/src/redis/queries.rs:429
/// Returns an error if scanning, reading, parsing, or deserializing instrument closes fails.
pub async fn load_instrument_closes(
con: &ConnectionManager,
trader_key: &str,
encoding: SerializationEncoding,
) -> anyhow::Result<AHashMap<InstrumentId, InstrumentClose>> {
let prefix = format!("{trader_key}{REDIS_DELIMITER}{INSTRUMENT_CLOSES}{REDIS_DELIMITER}");
let pattern = format!("{prefix}*");
log::debug!("Loading {pattern}");
let mut con = con.clone();
let keys = Self::scan_keys(&mut con, pattern).await?;
let values = Self::read_bulk(&con, &keys).await?;
let mut closes = AHashMap::with_capacity(keys.len());
for (key, value) in keys.into_iter().zip(values) {
let instrument_id = parse_instrument_key(&key, &prefix)?;
let value = value
.ok_or_else(|| anyhow::anyhow!("Instrument close not found in Redis: {key}"))?;
let close: InstrumentClose = Self::deserialize_payload(encoding, &value)?;
anyhow::ensure!(
close.instrument_id == instrument_id,
"Instrument close key ID {instrument_id} did not match payload ID {}",
close.instrument_id,
);
closes.insert(instrument_id, close);
}
log::debug!("Loaded {} instrument close(s)", closes.len());
Ok(closes)
}
/// Loads all synthetic instruments for `trader_key` using the specified `encoding`.
///
/// # Errors
///
/// Returns an error if scanning keys or reading synthetic instrument data fails.View on GitHub (pinned to 18893faf8b)
Solutions
- Check the named key in Redis (redis-cli GET) — if expired/deleted, re-write the instrument close.
- Rebuild or clean the instrument-close index so it no longer lists missing keys.
- Avoid TTLs on values while index entries have none, or set matching TTLs.
- Re-snapshot the cache from a fresh session to regenerate consistent index + values.
Example fix
// before: value keys with TTL, index without TTL -> nil slots on read redis.setex(value_key, 3600, payload); redis.sadd(index_key, value_key); // after: persist values (no TTL) while indexed, or purge index entries on expiry redis.set(value_key, payload);
Defensive patterns
Strategy: validation
Validate before calling
// Rust: verify all indexed keys exist before loading closes
async fn all_keys_exist(con: &mut ConnectionManager, keys: &[String]) -> bool {
let values: Vec<Option<Vec<u8>>> = redis::cmd("MGET").arg(keys)
.query_async(con).await.unwrap_or_default();
values.iter().all(|v| v.is_some())
} Try / catch
match load_instrument_closes(&mut con, trader_key, encoding).await {
Ok(closes) => closes,
Err(e) if e.to_string().contains("not found in Redis") => {
// purge stale index entry or re-write the missing value, then retry once
rebuild_index(&mut con, trader_key).await?;
load_instrument_closes(&mut con, trader_key, encoding).await?
}
Err(e) => return Err(e),
} Prevention
- Do not apply short TTLs to value keys whose index entries are persistent.
- Enable Redis persistence (AOF/RDB) so value keys survive restarts along with the index.
- Periodically reconcile index entries against existing value keys.
When it happens
Trigger: Calling load_instrument_closes / load_all when the Redis index of instrument-close keys contains a key whose value has expired (TTL), was deleted, or the bulk read (MGET) returned a nil slot.
Common situations: Values written with an expiry_ms TTL that later expired while the index entry persisted; manual deletion of value keys; Redis persistence restore that lost values but kept the index; replica with partial data.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Cannot process partial quote for {instrument_id}: missing bi
- Cannot process partial quote for {instrument_id}: missing as
- Cannot process partial quote for {instrument_id}: missing bi
- Cannot process partial quote for {instrument_id}: missing as
- Failed to send to channel: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1bd4cbb990cce4e8.
Report an issue: GitHub.