nautechsystems/nautilus_trader · error

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

Error message

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

What it means

register_arrow inserts an Arrow schema/encoder/decoder triple into the custom-data registry keyed by type name. Duplicate type names are rejected with this error rather than overwriting an existing registration, keeping the Arrow encode/decode path deterministic.

Source

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

    };
    Ok(Some(Data::Custom(custom)))
}

/// Registers Arrow schema, encoder, and decoder for the given custom data type name.
///
/// # Errors
/// Returns an error if the type is already registered for Arrow.
#[cfg(feature = "arrow")]
pub fn register_arrow(
    type_name: &str,
    schema: Arc<Schema>,
    encoder: ArrowEncoder,
    decoder: ArrowDecoder,
) -> Result<(), anyhow::Error> {
    let reg = registries();
    match reg.arrow.entry(type_name.to_string()) {
        Entry::Occupied(_) => {
            anyhow::bail!("Custom data type \"{type_name}\" is already registered for Arrow");
        }
        Entry::Vacant(v) => {
            v.insert((schema, encoder, decoder));
            Ok(())
        }
    }
}

/// Registers Arrow schema, encoder, and decoder 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`).
#[cfg(feature = "arrow")]
pub fn ensure_arrow_registered(
    type_name: &str,
    schema: Arc<Schema>,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make registration idempotent (Once lock, checked init, or catch-and-ignore this specific error when the registration is identical).
  2. Ensure the encoder/decoder/schema setup runs exactly once per process.
  3. Rename the type if a genuine conflict between different types exists.

Example fix

// before
register_arrow("MyData", schema, enc, dec)?;
// after
if let Err(e) = register_arrow("MyData", schema, enc, dec) {
    if !e.to_string().contains("already registered") { return Err(e); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust — guard with process-wide init
static ARROW_INIT: OnceLock<()> = OnceLock::new();
// call inside: ARROW_INIT.get_or_init(|| register_arrow(name, schema, enc, dec).unwrap());

Try / catch

// Rust
match register_arrow(type_name, schema, enc, dec) {
    Ok(()) => (),
    Err(e) if e.to_string().contains("already registered for Arrow") => (), // treat as success
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling register_arrow twice with the same type_name — repeated initialization, module re-import in Python, or two crates registering Arrow support for the same type.

Common situations: Test suites running registration per test; notebook re-runs; adapter reload logic that lacks an idempotence guard.

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/7ad1f7fa5819901c. Report an issue: GitHub.