nautechsystems/nautilus_trader · error

Custom data type "{type_name}" is already registered for JSO

Error message

Custom data type "{type_name}" is already registered for JSON

What it means

register_json_deserializer adds a JSON deserializer to the custom-data registry keyed by type name. The registry forbids duplicates, so registering the same type name twice bails with this error instead of silently overwriting the existing deserializer.

Source

Thrown at crates/model/src/data/registry.rs:75

        json: DashMap::new(),
        #[cfg(feature = "arrow")]
        arrow: DashMap::new(),
    })
}

/// Registers a JSON deserializer for the given custom data type name.
/// When `Data::deserialize` sees this type name, it will call this function.
///
/// # Errors
/// Returns an error if the type is already registered.
pub fn register_json_deserializer(
    type_name: &str,
    deserializer: JsonDeserializer,
) -> Result<(), anyhow::Error> {
    let reg = registries();
    match reg.json.entry(type_name.to_string()) {
        Entry::Occupied(_) => {
            anyhow::bail!("Custom data type \"{type_name}\" is already registered for JSON");
        }
        Entry::Vacant(v) => {
            v.insert(deserializer);
            Ok(())
        }
    }
}

/// Registers a JSON deserializer for the given custom data type name if not already registered.
/// If the type is already registered, returns `Ok(())` without overwriting (idempotent).
/// Use this where repeated registration can occur (e.g. module init).
///
/// # Errors
/// Does not return an error (idempotent insert into `DashMap`).
pub fn ensure_json_deserializer_registered(
    type_name: &str,
    deserializer: JsonDeserializer,
) -> Result<(), anyhow::Error> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Call registration only once, e.g. with a std::sync::Once / lazy static or an idempotent init guard.
  2. Check first (or catch this error) and treat 'already registered' as success in idempotent init paths.
  3. Use distinct type names if two genuinely different types collide.

Example fix

// before
register_custom_data_json("MyData", deser)?; // fails on second init
// after
static INIT: Once = Once::new();
INIT.call_once(|| register_custom_data_json("MyData", deser).unwrap());
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust — check before registering
// if registry already contains key, skip (expose a lookup or maintain your own Once)

Try / catch

// Rust
if let Err(e) = register_json_deserializer(type_name, deser) {
    if e.to_string().contains("already registered") { Ok(()) } else { Err(e) } // idempotent
} else { Ok(()) }

Prevention

When it happens

Trigger: Calling register_json_deserializer (or register_custom_data_json) twice for the same type_name, e.g. on module re-import, repeated adapter initialization, or two crates registering the same logical type.

Common situations: Python modules reloaded in notebooks or tests invoking registration each run; a library and application both registering the same custom type; hot-reloading adapters.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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