{"record":{"id":"3037f8791828c882","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-instrument-id-from-key-key-e","errorCode":null,"errorMessage":"Failed to parse instrument ID from key '{key}': {e}","messagePattern":"Failed to parse instrument ID from key '(.+?)': (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/redis/queries.rs","lineNumber":1023,"sourceCode":"    async fn read_hset(conn: &mut ConnectionManager, key: &str) -> anyhow::Result<Vec<Bytes>> {\n        let result: HashMap<String, String> = conn.hgetall(key).await?;\n        let json = serde_json::to_string(&result)?;\n        Ok(vec![Bytes::from(json.into_bytes())])\n    }\n\n    async fn read_list(conn: &mut ConnectionManager, key: &str) -> anyhow::Result<Vec<Bytes>> {\n        let result: Vec<Bytes> = conn.lrange(key, 0, -1).await?;\n        Ok(result)\n    }\n}\n\nfn parse_instrument_key(key: &str, prefix: &str) -> anyhow::Result<InstrumentId> {\n    let value = key\n        .strip_prefix(prefix)\n        .filter(|value| !value.is_empty())\n        .ok_or_else(|| anyhow::anyhow!(\"Invalid instrument key '{key}'\"))?;\n    InstrumentId::from_str(value)\n        .map_err(|e| anyhow::anyhow!(\"Failed to parse instrument ID from key '{key}': {e}\"))\n}\n\nfn is_timestamp_field(key: &str) -> bool {\n    let expire_match = key == \"expire_time_ns\";\n    let ts_match = key.starts_with(\"ts_\");\n    expire_match || ts_match\n}\n\nfn convert_timestamps(value: &mut Value) {\n    match value {\n        Value::Object(map) => {\n            for (key, v) in map {\n                if is_timestamp_field(key)\n                    && let Value::Number(n) = v\n                    && let Some(n) = n.as_u64()\n                {\n                    let dt = Timestamp::from_nanosecond(i128::from(n))\n                        .expect(\"UnixNanos is within Jiff's timestamp range\");","sourceCodeStart":1005,"sourceCodeEnd":1041,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/redis/queries.rs#L1005-L1041","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncon.set(\"instruments:EURUSD\", payload); // missing venue -> parse fails\n// after\ncon.set(\"instruments:EURUSD.IDEAL\", payload);","handlingStrategy":"validation","validationCode":"// Rust: validate instrument id portion before writing keys\nfn instrument_key_is_valid(key: &str, prefix: &str) -> bool {\n    key.strip_prefix(prefix)\n        .map(|rest| InstrumentId::from_str(rest).is_ok())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match load_instruments(&mut con, trader_key, encoding).await {\n    Ok(instruments) => instruments,\n    Err(e) if e.to_string().contains(\"Failed to parse instrument ID\") => {\n        tracing::error!(\"malformed instrument key: {e}; fix or delete the key\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["redis","instrument-id","key-format","parsing"],"backgroundTag":"invalid-identifier-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}