PluginManagerCore.getPlugin is now Internal

Hi, I’m wondering why PluginManagerCore.getPlugin(id: PluginId?) is Internal in IJ 2026.2 EAP.
I’m using it since a long time to read the version of my plugin, which is very useful when generating an error report.

The commit that added @Internal:

[plugins] IJPL-244315 Do not allow plugins to enable or disable plugins via PluginManagerCore

GitOrigin-RevId: 7b3bbd9dc2769784e0bee284b8eb86faeb77d447

I understand that we should not be able to enable or disable a plugin (and the corresponding methods are now deprecated), but removing access to getPlugin may be too much.
I can’t find a replacement method to read the version of an installed plugin. Some help would be appreciated.

Thx

Thank you so much for the use case, we can introduce dedicated API for it

Basically plugins should not access IdeaPluginDescriptor of other plugins as we noticed that some plugins are trying to reflection-patch others. IdeaPluginDescriptor is rather implementation detail and not really an API to use

PluginManger still allows accessing the descriptors, as it delegates to PluginManagerCore.

Accessing other plugins‘ descriptors would still be useful, even if read-only. Wouldn‘t there always be ways to abuse reflection?

To read the own plugin‘s descriptor, there‘s PluginAwareClassLoader, but I‘m not sure if that‘s the best, recommended way…

It is usually OK to know everything about plugins, what is not good is access to their Plugin classloader

We take this seriously, such usage (reflective access to other plugins) is a road to ban in the Marketplace

Thx. For now, I think I will read the plugin version from my plugin.xml (the good old getClass().getResourceAsStream("/META-INF/plugin.xml"))). I’m not sure if it works in all cases, but it will allow me to support both older versions (2025-2026.1) and newer versions of the IDEs.

We will follow up with proper APIs in master to read all information on plugins, versions, descriptions, etc, as those are no secret

Why not just cast the classloader of one of your own classes to PluginAwareClassloader and get the version from there? That should work for old and new…

Good idea! Just tried and it seems to work well.

Disabling plugins

I think a valid use case to turn off or disable other plugins is, when several provide the same functionality and thus should not be installed at the same time, like file types for the same extensions, run configuration overlap, and more.

For example, BashSupport Pro and the Shell plugin provide a similar set of features.
If possible, both should not be used and installed at the same time. For better UX BashSupport Pro has a wizard to let the user decide if Shell should be disabled or not.
With the changes of 2026.2, this won‘t be possible anymore.

Is a clear, user-initiated action a valid use case to disable another plugin?

If not, what do you recommend?
Asking the user „please close this dialog, go to settings, locate the plugin X, click disable, then restart“ seems not like good UX or a good alternative to me.

I can‘t use „incompatible with“, because some IDE’s features (iirc, e.g. CLion + Makefile support, others) depend on Shell.

Accessing classloader

There‘s another case not possible anymore with 2026.2 for me:
Because BashSupport Pro is providing Shell run configuration compatibility, it unregisters Shell‘s runConfigurationProducer via „ExtensionPoint.unregisterExtension(Class)“ when both are enabled.
The method variant with „class“ is used to prevent instantiating the extension unnecessarily. To locate the class without instantiating the extension, I access the classloader of the other plugin (but not using reflection).

Not doing this would make two providers for the same run configurations available at the same time, which ends up with unpredictable results, bad UX, exceptions and more.

I‘m not sure which usages made JetBrains restrict the API this much, I just hope there‘s a way to allow the valid use cases while still preventing abuse…

Thanks!
Joachim

We know that, but it ultimately requires user attention and approval and may not be allowed to plugins to do silently

I hope we can just introduce a switch-off toggle extension on our side in the Shell Script plugin so you can signal the built-in extension to unregister

I use this API in my (company-private) plugin to disable the Kubernetes plugin if it’s enabled, because it aggressively claims the file types that my plugin claims, and disabling it programmatically was the easiest way I could find to stop it from happening.

As far as I know we have a simpler way for you to redefine file types using platform APIs, it does not require disabling plugins

Please UNmark those APIs as internal until the “proper” APIs publicly available, it always hard to keep compatibility cross multiple major IntelliJ versions.

My cases are:

PluginManagerCore.getPlugin(PluginId) for get my plugin’s version.
PluginManagerCore.enablePlugin(PluginId) to ask user enable/install the license plugin com.intellij.marketplace after user paid. (useful for Android Studio / Huawei DevEco Studio etc)
PluginManagerCore.getPlugins() to check if there any crack plugins by Nasller (which is not published in JetBrains Marketplace, and the crack plugin still actively updated by Nasller)

When we introduce such a regulation it does not affect any existing usages, it blocks any new usages though.

And when the replacement is available we will ask everyone to migrate.

At the moment we have plans to cover:

  • PluginManagerCore.getPlugin(PluginId) – alternative API without access to ClassLoader
  • PluginManagerCore.getPlugins() – alternative API without access to IdeaPluginDescriptor
  • PluginManagerCore.enablePlugin(PluginId) – suggestion popup/dialog API
  • PluginManagerCore.disablePlugin(PluginId) – plugin conflicts dialog API

@zhihao Please note that you now may safely depend on this plugin in your plugin to require it. It will be installed automatically in Android Studio by dependency and on JetBrains IDEs it is included always

How exactly does that work?
When I have a plugin build for 261.* and then publish a build for 262.*, wouldn’t the new upload be blocked because of internal API?

If the new API is planned for 262, then things should be fine as we’re still early in the EAP.