{"record":{"id":"7c674dbd270a958b","repo":"nautechsystems/nautilus_trader","slug":"invalid-exec-algorithm-params","errorCode":null,"errorMessage":"Invalid exec algorithm params","messagePattern":"Invalid exec algorithm params","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/models/orders.rs","lineNumber":1155,"sourceCode":"        let linked_order_ids = row\n            .try_get::<Option<Vec<String>>, _>(\"linked_order_ids\")\n            .ok()\n            .and_then(|ids| ids.map(|ids| ids.into_iter().map(ClientOrderId::from).collect()));\n        let parent_order_id = row\n            .try_get::<Option<&str>, _>(\"parent_order_id\")\n            .ok()\n            .and_then(|x| x.map(ClientOrderId::from));\n        let exec_algorithm_id = row\n            .try_get::<Option<&str>, _>(\"exec_algorithm_id\")\n            .ok()\n            .and_then(|x| x.map(ExecAlgorithmId::from));\n        let exec_algorithm_params: Option<IndexMap<Ustr, Ustr>> = row\n            .try_get::<Option<serde_json::Value>, _>(\"exec_algorithm_params\")\n            .ok()\n            .and_then(|x| {\n                x.map(|x| {\n                    serde_json::from_value::<IndexMap<String, String>>(x)\n                        .expect(\"Invalid exec algorithm params\")\n                })\n            })\n            .map(|x| {\n                x.into_iter()\n                    .map(|(k, v)| (Ustr::from(k.as_str()), Ustr::from(v.as_str())))\n                    .collect()\n            });\n        let exec_spawn_id = row\n            .try_get::<Option<&str>, _>(\"exec_spawn_id\")\n            .ok()\n            .and_then(|x| x.map(ClientOrderId::from));\n        let tags = tags_from_row(row);\n        let init_id = row.try_get::<&str, _>(\"init_id\").map(UUID4::from)?;\n        let ts_init = row.try_get::<String, _>(\"ts_init\").map(UnixNanos::from)?;\n        let ts_last = row.try_get::<String, _>(\"ts_last\").map(UnixNanos::from)?;\n\n        let snapshot = OrderSnapshot {\n            trader_id,","sourceCodeStart":1137,"sourceCodeEnd":1173,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/models/orders.rs#L1137-L1173","documentation":"When loading an order row, the `exec_algorithm_params` JSONB column is deserialized into `IndexMap<String, String>` and unwrapped with expect(). The panic means the JSON in that column is not an object of string-to-string pairs (wrong JSON shape or types), so the row cannot be hydrated.","triggerScenarios":"Calling `OrderModel::from_row` where `exec_algorithm_params` contains e.g. a JSON array, a nested object (`{\"a\": {\"b\": 1}}`), numeric/boolean values (`{\"period\": 10}` instead of `\"10\"`), or invalid JSON entirely.","commonSituations":"Custom exec-algorithm code writing params with numeric values instead of strings; manual SQL updates to the JSONB column; schema drift between nautilus versions on how params are stored.","solutions":["Inspect the column: `SELECT id, exec_algorithm_params FROM orders WHERE jsonb_typeof(exec_algorithm_params) <> 'object'` and fix values","Make the writer stringify all param values before storing (json values as strings)","Cast numbers at read time by deserializing into `IndexMap<String, serde_json::Value>` and coercing, or a struct with #[serde(untyped)] handling","Replace expect with error propagation (`?`) so one bad row doesn't abort the whole query"],"exampleFix":"// before\nserde_json::from_value::<IndexMap<String, String>>(x).expect(\"Invalid exec algorithm params\")\n// after\nserde_json::from_value::<IndexMap<String, serde_json::Value>>(x)\n    .map_err(|e| ModelError::Parse(format!(\"invalid exec_algorithm_params: {e}\")))?\n    .into_iter()\n    .map(|(k, v)| (Ustr::from(&k), Ustr::from(&v.to_string().trim_matches('\"').to_string())))\n    .collect()","handlingStrategy":"validation","validationCode":"fn valid_exec_params(v: Option<&serde_json::Value>) -> bool {\n    v.map(|v| matches!(v, serde_json::Value::Object(m)\n        if m.values().all(|x| matches!(x, serde_json::Value::String(_))))).unwrap_or(true)\n}","typeGuard":"fn is_string_map(v: &serde_json::Value) -> bool {\n    matches!(v, Value::Object(m) if m.values().all(|x| matches!(x, Value::String(_))))\n}","tryCatchPattern":"let params = serde_json::from_value::<IndexMap<String, String>>(x)\n    .map_err(|e| ModelError::Parse(format!(\"row {}: invalid exec_algorithm_params: {e}\", row_id)))?;","preventionTips":["Stringify all param values before writing to JSONB","Never hand-edit JSONB columns; use the model's writer path","Add a JSON schema check (object of strings) at insert time","Round-trip test exec algorithm params persistence"],"tags":["rust","sql","postgres","json","panic"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}