nautechsystems/nautilus_trader · error

Rust extractor factory for "{type_name}" is already register

Error message

Rust extractor factory for "{type_name}" is already registered

What it means

register_rust_extractor_factory inserts a Rust extractor factory into a global registry keyed by type name. If a factory with the same type_name already exists, the library refuses to overwrite it and bails, because duplicate registration would make extractor resolution ambiguous. It is a startup/initialization-time invariant of the plugin/extractor registry.

Source

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

    RUST_EXTRACTOR_FACTORIES.get_or_init(DashMap::new)
}

/// Registers a factory that produces a `PyExtractor` for the given type name.
/// Crates (e.g. persistence) call this at load time for each Rust custom data type.
/// When `register_custom_data_class(cls)` is called with that type's class, the factory is invoked
/// and the extractor is registered in the main `PyExtractor` registry.
///
/// # Errors
/// Returns an error if the type name is already registered.
#[cfg(feature = "python")]
pub fn register_rust_extractor_factory(
    type_name: &str,
    factory: RustExtractorFactory,
) -> Result<(), anyhow::Error> {
    let reg = rust_extractor_factories();
    match reg.entry(type_name.to_string()) {
        Entry::Occupied(_) => {
            anyhow::bail!("Rust extractor factory for \"{type_name}\" is already registered");
        }
        Entry::Vacant(v) => {
            v.insert(factory);
            Ok(())
        }
    }
}

/// Registers a factory that produces a `PyExtractor` for the given 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 load).
///
/// # Errors
/// Does not return an error (idempotent insert into `DashMap`).
#[cfg(feature = "python")]
pub fn ensure_rust_extractor_factory_registered(
    type_name: &str,
    factory: RustExtractorFactory,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check if the type_name is already registered before calling register_rust_extractor (inspect the registry map) and skip or log instead
  2. Deduplicate registration code so each extractor type registers exactly once at startup
  3. If intentional replacement is needed, remove the existing entry first or use a registration API that allows overwrite, rather than re-registering
  4. In tests, use a once-guard (e.g. std::sync::Once or a static AtomicBool) so setup registers only once per process

Example fix

// before
register_rust_extractor("MyExtractor", factory)?;
// after
if !is_rust_extractor_registered("MyExtractor") {
    register_rust_extractor("MyExtractor", factory)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if rust_extractor_factory_registered(type_name) {
    return; // already registered, skip
}
register_rust_extractor(type_name, factory)?;

Try / catch

match register_rust_extractor(type_name, factory) {
    Err(e) if e.to_string().contains("already registered") => { /* treat as idempotent success */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling register_rust_extractor twice for the same type_name, or registering the same extractor from two modules/tests in one process (the registry is global). Static init code that runs more than once (e.g. a library loaded twice or a test harness re-registering) also triggers it.

Common situations: Two extractor crates both register the same extractor type; a binary links two versions of a crate that each register; test code registers in setup that runs per-test; duplicated registration added after a refactor/merge.

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