{"record":{"id":"06ae0aa190595d20","repo":"nautechsystems/nautilus_trader","slug":"customdata-registry-returned-non-custom-data","errorCode":null,"errorMessage":"CustomData registry returned non-custom data","messagePattern":"CustomData registry returned non-custom data","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/msgbus/external/mod.rs","lineNumber":591,"sourceCode":") -> anyhow::Result<Option<CustomData>> {\n    let Some(data) = deserialize_custom_from_json(custom_type_name.as_str(), value)? else {\n        log::warn!(\n            \"External custom payload type '{custom_type_name}' is not registered for inbound republishing\"\n        );\n        return Ok(None);\n    };\n\n    let envelope_type_name = value\n        .get(\"type\")\n        .and_then(serde_json::Value::as_str)\n        .context(\"CustomData JSON missing 'type' field\")?;\n    anyhow::ensure!(\n        envelope_type_name == custom_type_name.as_str(),\n        \"CustomData envelope type '{envelope_type_name}' does not match message type '{custom_type_name}'\"\n    );\n\n    let Data::Custom(custom) = data else {\n        anyhow::bail!(\"CustomData registry returned non-custom data\");\n    };\n\n    Ok(Some(custom))\n}\n","sourceCodeStart":573,"sourceCodeEnd":596,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/msgbus/external/mod.rs#L573-L596","documentation":"decode_custom_data_value looks up a registered custom data type and expects the registry to return a Data::Custom variant. If the decoded Data carries any other variant, the internal registry/decoder contract is broken and the code bails. This guards an internal invariant between the CustomData envelope type and the decoded payload.","triggerScenarios":"Calling decode_custom_data_payload on a payload whose registered decoder returns a Data value that is not Data::Custom — i.e. the envelope type name matched a custom type name but the decoded value deserialized into a non-custom variant.","commonSituations":"A custom data type was re-registered or shadowed so its decoder resolves to a built-in Data variant; version skew between a publisher serializing CustomData and a consumer whose registry maps the type name to different code; hand-written decoders registered for type names that collide with core types.","solutions":["Inspect the registered decoder for the type name in the preceding ensure! check and confirm it constructs Data::Custom.","Re-register the custom type with the correct decoder so the registry round-trips CustomData.","Check that publisher and consumer use matching versions of the custom data type definition."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before decoding, confirm the registered decoder for this type name is the custom one\nif let Some(decoder) = registry.get(&type_name) {\n    assert!(decoder.produces_custom_data(), \"decoder for {type_name} must yield Data::Custom\");\n}","typeGuard":"fn is_custom(data: &Data) -> bool { matches!(data, Data::Custom(_)) }","tryCatchPattern":"match decode_custom_data_payload(&payload, &registry) {\n    Ok(Some(custom)) => handle(custom),\n    Ok(None) => {},\n    Err(e) => log::error!(\"custom data decode failed: {e}\"),\n}","preventionTips":["Keep custom type registrations in one module so decoders cannot be shadowed.","Round-trip test every registered custom type (serialize then decode) in unit tests.","Pin matching versions of custom data definitions across publisher and consumer."],"tags":["internal","custom-data","message-bus","registry"],"backgroundTag":"internal-invariant-violation","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"}