nautechsystems/nautilus_trader · error · anyhow::Error

CustomData registry returned non-custom data

Error message

CustomData registry returned non-custom data

What it means

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.

Source

Thrown at crates/common/src/msgbus/external/mod.rs:591

) -> anyhow::Result<Option<CustomData>> {
    let Some(data) = deserialize_custom_from_json(custom_type_name.as_str(), value)? else {
        log::warn!(
            "External custom payload type '{custom_type_name}' is not registered for inbound republishing"
        );
        return Ok(None);
    };

    let envelope_type_name = value
        .get("type")
        .and_then(serde_json::Value::as_str)
        .context("CustomData JSON missing 'type' field")?;
    anyhow::ensure!(
        envelope_type_name == custom_type_name.as_str(),
        "CustomData envelope type '{envelope_type_name}' does not match message type '{custom_type_name}'"
    );

    let Data::Custom(custom) = data else {
        anyhow::bail!("CustomData registry returned non-custom data");
    };

    Ok(Some(custom))
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the registered decoder for the type name in the preceding ensure! check and confirm it constructs Data::Custom.
  2. Re-register the custom type with the correct decoder so the registry round-trips CustomData.
  3. Check that publisher and consumer use matching versions of the custom data type definition.
Defensive patterns

Strategy: try-catch

Validate before calling

// before decoding, confirm the registered decoder for this type name is the custom one
if let Some(decoder) = registry.get(&type_name) {
    assert!(decoder.produces_custom_data(), "decoder for {type_name} must yield Data::Custom");
}

Type guard

fn is_custom(data: &Data) -> bool { matches!(data, Data::Custom(_)) }

Try / catch

match decode_custom_data_payload(&payload, &registry) {
    Ok(Some(custom)) => handle(custom),
    Ok(None) => {},
    Err(e) => log::error!("custom data decode failed: {e}"),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/06ae0aa190595d20. Report an issue: GitHub.