nautechsystems/nautilus_trader · error
Failed to parse instrument ID from key '{key}': {e}
Error message
Failed to parse instrument ID from key '{key}': {e} What it means
After successfully stripping the prefix, parse_instrument_key attempts InstrumentId::from_str on the remainder. If the remainder is not a valid 'SYMBOL.VENUE' identifier, the parse error is wrapped as 'Failed to parse instrument ID from key'. The key had the right prefix but a malformed instrument portion.
Source
Thrown at crates/infrastructure/src/redis/queries.rs:1023
async fn read_hset(conn: &mut ConnectionManager, key: &str) -> anyhow::Result<Vec<Bytes>> {
let result: HashMap<String, String> = conn.hgetall(key).await?;
let json = serde_json::to_string(&result)?;
Ok(vec![Bytes::from(json.into_bytes())])
}
async fn read_list(conn: &mut ConnectionManager, key: &str) -> anyhow::Result<Vec<Bytes>> {
let result: Vec<Bytes> = conn.lrange(key, 0, -1).await?;
Ok(result)
}
}
fn parse_instrument_key(key: &str, prefix: &str) -> anyhow::Result<InstrumentId> {
let value = key
.strip_prefix(prefix)
.filter(|value| !value.is_empty())
.ok_or_else(|| anyhow::anyhow!("Invalid instrument key '{key}'"))?;
InstrumentId::from_str(value)
.map_err(|e| anyhow::anyhow!("Failed to parse instrument ID from key '{key}': {e}"))
}
fn is_timestamp_field(key: &str) -> bool {
let expire_match = key == "expire_time_ns";
let ts_match = key.starts_with("ts_");
expire_match || ts_match
}
fn convert_timestamps(value: &mut Value) {
match value {
Value::Object(map) => {
for (key, v) in map {
if is_timestamp_field(key)
&& let Value::Number(n) = v
&& let Some(n) = n.as_u64()
{
let dt = Timestamp::from_nanosecond(i128::from(n))
.expect("UnixNanos is within Jiff's timestamp range");View on GitHub (pinned to 18893faf8b)
Solutions
- Fix or delete the offending Redis key so it ends with a valid '<SYMBOL>.<VENUE>' suffix.
- Validate instrument IDs with InstrumentId::from_str before writing them to Redis in custom tooling.
- Check for symbols containing characters incompatible with the identifier format and re-map them.
- Re-snapshot the cache to regenerate conforming keys from in-memory InstrumentIds.
Example fix
// before
con.set("instruments:EURUSD", payload); // missing venue -> parse fails
// after
con.set("instruments:EURUSD.IDEAL", payload); Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate instrument id portion before writing keys
fn instrument_key_is_valid(key: &str, prefix: &str) -> bool {
key.strip_prefix(prefix)
.map(|rest| InstrumentId::from_str(rest).is_ok())
.unwrap_or(false)
} Try / catch
match load_instruments(&mut con, trader_key, encoding).await {
Ok(instruments) => instruments,
Err(e) if e.to_string().contains("Failed to parse instrument ID") => {
tracing::error!("malformed instrument key: {e}; fix or delete the key");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Always write instrument keys as '<prefix>:<SYMBOL>.<VENUE>' including the venue suffix.
- Validate InstrumentId::from_str in import/migration scripts before writing to Redis.
- Avoid raw symbol strings in keys; serialize from in-memory InstrumentId instances.
When it happens
Trigger: load_instruments / load_instrument_closes (via load_all) encountering keys like 'instruments:EURUSD' (missing venue), 'instruments:.IDEAL' (empty symbol), or keys containing unexpected extra segments the InstrumentId parser rejects.
Common situations: Instruments written with non-standard symbol strings; keys hand-crafted by import scripts missing the venue suffix; symbol changes introducing characters unsupported by InstrumentId; colons inside symbols interacting with the delimiter scheme.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid `key`, missing a '{REDIS_DELIMITER}' delimiter, was
- Invalid instrument key '{key}'
- Invalid `external_order_claims` instrument ID {claim}: {e}
- {FAILED}: {e}
- Cannot extract market ID from {instrument_id}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3037f8791828c882.
Report an issue: GitHub.