{"record":{"id":"4a609f3d79d8f34f","repo":"nautechsystems/nautilus_trader","slug":"customdata-must-be-valid-json-e","errorCode":null,"errorMessage":"CustomData must be valid JSON: {e}","messagePattern":"CustomData must be valid JSON: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/queries.rs","lineNumber":1620,"sourceCode":"            r#\"SELECT * FROM \"signal\" WHERE name = $1 ORDER BY ts_init ASC\"#,\n        )\n        .bind(name)\n        .fetch_all(pool)\n        .await\n        .map(|rows| rows.into_iter().map(|row| row.0).collect())\n        .map_err(|e| anyhow::anyhow!(\"Failed to load signals: {e}\"))\n    }\n\n    /// Inserts a `CustomData` entry via the provided `pool`.\n    ///\n    /// Serializes the model `CustomData` to full JSON and stores it in the JSONB `value` column.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the SQL INSERT operation fails.\n    pub async fn add_custom_data(pool: &PgPool, data: &CustomData) -> anyhow::Result<()> {\n        let json_bytes = serde_json::to_vec(data)\n            .map_err(|e| anyhow::anyhow!(\"CustomData must be valid JSON: {e}\"))?;\n        let value_json: serde_json::Value = serde_json::from_slice(&json_bytes)\n            .map_err(|e| anyhow::anyhow!(\"CustomData value must be valid JSON: {e}\"))?;\n        let data_type_obj = value_json\n            .get(\"data_type\")\n            .and_then(|v| v.as_object())\n            .ok_or_else(|| anyhow::anyhow!(\"CustomData JSON missing data_type\"))?;\n        let data_type_name = data_type_obj\n            .get(\"type_name\")\n            .and_then(|v| v.as_str())\n            .unwrap_or(\"\");\n        let metadata_json = data_type_obj\n            .get(\"metadata\")\n            .cloned()\n            .unwrap_or_else(|| serde_json::Value::Object(serde_json::Map::new()));\n        let identifier = data_type_obj\n            .get(\"identifier\")\n            .and_then(|v| v.as_str())\n            .unwrap_or(\"\");","sourceCodeStart":1602,"sourceCodeEnd":1638,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/queries.rs#L1602-L1638","documentation":"Raised in `add_custom_data` when `serde_json::to_vec(data)` fails to serialize the `CustomData` struct. Since CustomData is Rust data, this usually means a serialization error inside its payload (e.g., a map with non-string keys, or an internal Serialize impl returning an error). The library requires CustomData to round-trip through JSON because it is stored in a JSONB column.","triggerScenarios":"Calling `add_custom_data(pool, data)` with a CustomData whose inner value or metadata cannot be represented as JSON (non-string map keys, unsupported numeric types like NaN/Infinity in a JSON-restricted serializer, or a failing custom Serialize implementation).","commonSituations":"Custom data payloads containing f64 NaN/Infinity; user-defined data types with hand-written Serialize impls that error; non-string-key maps (e.g., HashMap<u32, _>) in metadata.","solutions":["Check the serde error in `{e}` for the exact field that failed to serialize.","Replace NaN/Infinity floats with valid JSON-representable values or strings.","Ensure map keys in the payload are strings (or convert before constructing CustomData).","Validate the payload round-trips with serde_json::to_vec before calling the API."],"exampleFix":"// before\nlet data = CustomData::new(my_value, ...); // my_value contains HashMap<u64, String>\nadd_custom_data(&pool, &data).await?;\n// after\nlet normalized = my_value.iter().map(|(k, v)| (k.to_string(), v.clone())).collect::<HashMap<String, _>>();\nserde_json::to_vec(&normalized).expect(\"valid JSON\");\nadd_custom_data(&pool, &CustomData::new(normalized, ...)).await?;","handlingStrategy":"validation","validationCode":"// verify the payload serializes before calling the API\nlet bytes = serde_json::to_vec(&data)\n    .map_err(|e| anyhow::anyhow!(\"CustomData not JSON-serializable: {e}\"))?;\nanyhow::ensure!(!bytes.is_empty(), \"empty CustomData payload\");","typeGuard":"fn is_json_serializable<T: serde::Serialize>(v: &T) -> bool {\n    serde_json::to_vec(v).is_ok()\n}","tryCatchPattern":null,"preventionTips":["Avoid NaN/Infinity floats in custom data payloads","Use string map keys in payloads and metadata","Derive Serialize instead of hand-writing it","Round-trip test payloads in unit tests"],"tags":["serde","json","serialization"],"backgroundTag":"json-marshal-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"}