{"record":{"id":"741d0df8824a6a37","repo":"docling-project/docling","slug":"opt-type-kind-r-already-registered-to-class-sel","errorCode":null,"errorMessage":"{opt_type.kind!r} already registered to class {self._classes[opt_type]!r}","messagePattern":"(.+?) already registered to class (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"docling/models/factories/base_factory.py","lineNumber":81,"sourceCode":"            if opt_cls.kind == kind:\n                return opt_cls(*args, **kwargs)\n        raise RuntimeError(self._err_msg_on_class_not_found(kind))\n\n    def _err_msg_on_class_not_found(self, kind: str):\n        msg = []\n\n        for opt, cls in self._classes.items():\n            msg.append(f\"\\t{opt.kind!r} => {cls!r}\")\n\n        msg_str = \"\\n\".join(msg)\n\n        return f\"No class found with the name {kind!r}, known classes are:\\n{msg_str}\"\n\n    def register(self, cls: Type[A], plugin_name: str, plugin_module_name: str):\n        opt_type = cls.get_options_type()\n\n        if opt_type in self._classes:\n            raise ValueError(\n                f\"{opt_type.kind!r} already registered to class {self._classes[opt_type]!r}\"\n            )\n\n        self._classes[opt_type] = cls\n        self._meta[opt_type] = FactoryMeta(\n            kind=opt_type.kind, plugin_name=plugin_name, module=plugin_module_name\n        )\n\n    def load_from_plugins(\n        self, plugin_name: Optional[str] = None, allow_external_plugins: bool = False\n    ):\n        plugin_name = plugin_name or self.plugin_name\n\n        plugin_manager = PluginManager(plugin_name)\n        plugin_manager.load_setuptools_entrypoints(plugin_name)\n\n        for plugin_name, plugin_module in plugin_manager.list_name_plugin():\n            plugin_module_name = str(plugin_module.__name__)  # type: ignore","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/factories/base_factory.py#L63-L99","documentation":"Raised as ValueError by BaseFactory.register when a plugin tries to register an options type that is already mapped to a class. The factory enforces one implementation class per options type to keep resolution deterministic.","triggerScenarios":"Registering two classes whose get_options_type() returns the same options class — e.g. a plugin re-registers a class already registered by docling-core, or two plugins vendored/duplicated copies of the same options class.","commonSituations":"Developing a plugin that subclasses or re-imports an existing options class and calls register() again; double import of a plugin under different module names; running registration both at import time and explicitly.","solutions":["Make the plugin idempotent: check `opt_type in factory.classes` before calling register, or guard registration behind a module-level flag.","Give your plugin its own distinct options subclass with a unique kind instead of reusing an existing options class.","Remove the duplicate import/registration path (e.g. registering both via entry point and via explicit import)."],"exampleFix":"# before\nclass MyModel(BaseModel):\n    ...\nfactory.register(MyModel, 'my_plugin', 'my_plugin.models')  # ValueError if re-imported\n\n# after\nif MyModel.get_options_type() not in factory.classes:\n    factory.register(MyModel, 'my_plugin', 'my_plugin.models')","handlingStrategy":"validation","validationCode":"opt_type = MyModel.get_options_type()\nif opt_type in factory.classes:\n    print(f'skip: {opt_type.kind!r} already registered to {factory.classes[opt_type]!r}')\nelse:\n    factory.register(MyModel, 'my_plugin', 'my_plugin.models')","typeGuard":"def needs_registration(factory, cls) -> bool:\n    return cls.get_options_type() not in factory.classes","tryCatchPattern":"try:\n    factory.register(cls, plugin_name, module_name)\nexcept ValueError as e:\n    if 'already registered' in str(e):\n        pass  # idempotent plugin load\n    else:\n        raise","preventionTips":["Make plugin registration idempotent (check factory.classes first).","Register each options type exactly once — give plugins their own options subclass.","Avoid importing the same plugin via two module paths."],"tags":["factory","plugins","registration","duplicate"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}