{"id":"cc55455db7932c26","repo":"python-poetry/poetry","slug":"the-poetry-plugin-must-be-an-instance-of-plugin-or","errorCode":null,"errorMessage":"The Poetry plugin must be an instance of Plugin or ApplicationPlugin","messagePattern":"The Poetry plugin must be an instance of Plugin or ApplicationPlugin","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/poetry/plugins/plugin_manager.py","lineNumber":90,"sourceCode":"    def ensure_project_plugins(cls, poetry: Poetry, io: IO) -> None:\n        ProjectPluginCache(poetry, io).ensure_plugins()\n\n    def load_plugins(self) -> None:\n        plugin_entrypoints = self.get_plugin_entry_points()\n\n        for ep in plugin_entrypoints:\n            self._load_plugin_entry_point(ep)\n\n    def get_plugin_entry_points(self) -> list[metadata.EntryPoint]:\n        return list(metadata.entry_points(group=self._group))\n\n    def activate(self, *args: Any, **kwargs: Any) -> None:\n        for plugin in self._plugins:\n            plugin.activate(*args, **kwargs)\n\n    def _add_plugin(self, plugin: Plugin) -> None:\n        if not isinstance(plugin, (Plugin, ApplicationPlugin)):\n            raise ValueError(\n                \"The Poetry plugin must be an instance of Plugin or ApplicationPlugin\"\n            )\n\n        self._plugins.append(plugin)\n\n    def _load_plugin_entry_point(self, ep: metadata.EntryPoint) -> None:\n        logger.debug(\"Loading the %s plugin\", ep.name)\n\n        plugin = ep.load()\n\n        if not issubclass(plugin, (Plugin, ApplicationPlugin)):\n            raise ValueError(\n                \"The Poetry plugin must be an instance of Plugin or ApplicationPlugin\"\n            )\n\n        self._add_plugin(plugin())\n\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/python-poetry/poetry/blob/92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54/src/poetry/plugins/plugin_manager.py#L72-L108","documentation":"Raised by PluginManager._add_plugin() when an object passed in is not an instance of Plugin or ApplicationPlugin. _add_plugin is the single chokepoint that registers activated plugins; the isinstance guard keeps the plugin list type-safe. This is an internal/programmatic API — end users rarely call it directly.","triggerScenarios":"Code calls PluginManager._add_plugin(some_obj) (or a subclass overrides it) with an object that is neither a Plugin nor an ApplicationPlugin — e.g. passing a bare class, an unrelated object, or an instance whose base classes were not imported correctly.","commonSituations":"A third-party entry point that registers a non-plugin object; a test harness that injects a mock without subclassing Plugin; an import error that silently loaded a stub class; a plugin author subclassing the wrong base (e.g. a generic object).","solutions":["Ensure the passed object subclasses poetry.plugins.plugin.Plugin or poetry.plugins.application_plugin.ApplicationPlugin.","Check the import path — the base class must be imported from poetry.plugins, not a stale local copy.","If using a mock in tests, subclass Plugin and override methods rather than passing a bare Mock.","Reproduce the call in a REPL and inspect type(obj).__mro__ to see why the isinstance check fails."],"exampleFix":"// before\nfrom poetry.plugins.plugin_manager import PluginManager\npm._add_plugin(MyRandomClass())\n\n// after\nfrom poetry.plugins.plugin import Plugin\nclass MyPlugin(Plugin):\n    def activate(self, application, io):\n        ...\npm._add_plugin(MyPlugin())","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"from poetry.plugins.plugin import Plugin\nfrom poetry.plugins.application_plugin import ApplicationPlugin\n\ndef is_valid_plugin(obj: object) -> bool:\n    return isinstance(obj, (Plugin, ApplicationPlugin))","tryCatchPattern":"from poetry.plugins.plugin_manager import PluginManager\n\ntry:\n    pm._add_plugin(candidate)\nexcept ValueError:\n    # candidate is not a Plugin/ApplicationPlugin; skip or wrap it\n    ...","preventionTips":["Always subclass Plugin or ApplicationPlugin when writing plugins.","Import base classes from the canonical poetry.plugins path, not local copies.","In tests, subclass the real base rather than mocking it.","Run a smoke import of each plugin in CI to catch type mistakes early."],"tags":["plugin","type-check","internal-api"],"analyzedSha":"92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54","analyzedAt":"2026-08-04T20:33:34.072Z","schemaVersion":2}