{"record":{"id":"307371ee340bebdd","repo":"nautechsystems/nautilus_trader","slug":"a-different-label-extractor-is-already-registere","errorCode":null,"errorMessage":"A different {label} extractor is already registered for '{type_name}'","messagePattern":"A different (.+?) extractor is already registered for '(.+?)'","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/python/factory.rs","lineNumber":70,"sourceCode":"    /// Registering the same extractor again succeeds without change, so a Python module\n    /// initializer can run more than once per process.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if a different extractor is already registered for the type name.\n    pub fn register(\n        &self,\n        type_name: String,\n        extractor: FactoryExtractor<T>,\n    ) -> anyhow::Result<()> {\n        let mut extractors = self.extractors_by_type.lock();\n\n        if let Some(registered) = extractors.get(&type_name) {\n            if std::ptr::fn_addr_eq(*registered, extractor) {\n                return Ok(());\n            }\n\n            anyhow::bail!(\n                \"A different {label} extractor is already registered for '{type_name}'\",\n                label = self.label\n            );\n        }\n\n        extractors.insert(type_name, extractor);\n        Ok(())\n    }\n\n    /// Extracts a Python object into a boxed factory.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if no extractor is registered for the Python type or extraction fails.\n    pub fn extract(&self, py: Python<'_>, factory: Py<PyAny>) -> PyResult<Box<T>> {\n        let type_name = factory\n            .getattr(py, \"__class__\")?\n            .getattr(py, \"__name__\")?","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/python/factory.rs#L52-L88","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfactory.register(\"MyData\", extractor_v1);\nfactory.register(\"MyData\", extractor_v2); // bails\n// after\nif !factory.has_extractor(\"MyData\") {\n    factory.register(\"MyData\", extractor_v2);\n}","handlingStrategy":"try-catch","validationCode":"# skip re-registration when the extractor is unchanged\nexisting = registry.get(type_name)\nif existing is not None and existing is not extractor:\n    raise RuntimeError(f\"extractor conflict for {type_name}\")","typeGuard":null,"tryCatchPattern":"try:\n    factory.register(type_name, extractor)\nexcept Exception as e:\n    if \"already registered\" in str(e):\n        log.debug(\"extractor for %s already registered\", type_name)","preventionTips":["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."],"tags":["registration","conflict","factory","python"],"backgroundTag":"conflicting-config-options","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}