nautechsystems/nautilus_trader · error · anyhow::Error
A different {label} extractor is already registered for '{ty
Error message
A different {label} extractor is already registered for '{type_name}' What it means
The Python factory's extractor registry allows each type name to have exactly one extractor for a given label. Registering a second, different extractor function for the same type_name bails; re-registering the identical function pointer is idempotent and returns Ok. This prevents silent overwriting of extractor behavior.
Source
Thrown at crates/common/src/python/factory.rs:70
/// Registering the same extractor again succeeds without change, so a Python module
/// initializer can run more than once per process.
///
/// # Errors
///
/// Returns an error if a different extractor is already registered for the type name.
pub fn register(
&self,
type_name: String,
extractor: FactoryExtractor<T>,
) -> anyhow::Result<()> {
let mut extractors = self.extractors_by_type.lock();
if let Some(registered) = extractors.get(&type_name) {
if std::ptr::fn_addr_eq(*registered, extractor) {
return Ok(());
}
anyhow::bail!(
"A different {label} extractor is already registered for '{type_name}'",
label = self.label
);
}
extractors.insert(type_name, extractor);
Ok(())
}
/// Extracts a Python object into a boxed factory.
///
/// # Errors
///
/// Returns an error if no extractor is registered for the Python type or extraction fails.
pub fn extract(&self, py: Python<'_>, factory: Py<PyAny>) -> PyResult<Box<T>> {
let type_name = factory
.getattr(py, "__class__")?
.getattr(py, "__name__")?View on GitHub (pinned to 18893faf8b)
Solutions
- Guard registration: only call register if the type name is not already registered, or reuse the same function object.
- Unregister/replace explicitly via the appropriate API before registering a different extractor, if supported.
- Rename one of the conflicting types or move registration to a single shared module.
Example fix
// before
factory.register("MyData", extractor_v1);
factory.register("MyData", extractor_v2); // bails
// after
if !factory.has_extractor("MyData") {
factory.register("MyData", extractor_v2);
} Defensive patterns
Strategy: try-catch
Validate before calling
# skip re-registration when the extractor is unchanged
existing = registry.get(type_name)
if existing is not None and existing is not extractor:
raise RuntimeError(f"extractor conflict for {type_name}") Try / catch
try:
factory.register(type_name, extractor)
except Exception as e:
if "already registered" in str(e):
log.debug("extractor for %s already registered", type_name) Prevention
- Centralize all extractor registration in one import-time module.
- Make extractors module-level singletons so re-registration compares equal pointers.
- Clear registries between tests or use per-test factory instances.
When it happens
Trigger: Calling register twice with two different extractor functions for the same type_name under the same factory label — typically during module init or repeated imports with differing implementations.
Common situations: Loading two plugin modules that both register extractors for the same custom type; hot-reloading code where a modified extractor function (new pointer) is registered again; test suites registering extractors globally without cleanup between tests.
Related errors
- Factory extractor '{name}' is already registered
- A different simulation module extractor is already registere
- Actor {actor_id} is already registered
- Failed to create config instance. Tried kwargs: {kwargs_err}
- Invalid `strategy_id` type
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/307371ee340bebdd.
Report an issue: GitHub.