2026.2 and now internal PluginManager API

,

I had updated a plugin for an early build of 2026.2, which worked okay.
Now I’m updating for 2026.2 rc and it’s ugly (and I’m quite frustrated with this EAP cycle).

PluginManager was made @Internal while there are still active users and without any period of deprecation. In my experience, that’s quite unusual. And it’s causing a lot of friction.
I expect that other plugin will only notice this when their build with an open until-build is flagged to be incompatible with 2026.2…

I know about the new PluginDetailsService.
But since it’s new in 2026.2, every plugin accessing plugin metadata (even its own) must create separate build for <2026.2 and >=2026.2 now. AFAIK most plugins have just one build for all major versions.

There’s no reliable way to fetch the own PluginDescriptor. There’s PluginAwareClassloader to access it, but it does not work in unit test mode, where a different classloader is used. Making (more) assumptions about test mode in code is IMHO a code smell.
How can I fetch my own plugin’s PluginDescriptor?

Without a PluginDescriptor the following properties are not available anymore (they are not in PluginDetails):

  • PluginDescriptor.getReleaseVersion()
  • PluginDescriptor.getReleaseDate()
  • PluginDescriptor.isLicenseOptional()

Similar, IdeaPluginDescriptor.getDependencies() is not accessible anymore.
I’m using it to prevent the dynamic unload of dependencies of my plugin to work around 5 years old platform bugs https://youtrack.jetbrains.com/issue/IJPL-1892 and https://youtrack.jetbrains.com/issue/IJPL-1115.
The “fix” would probably be to move to a v2 plugin descriptor, but it’s only good with 2025.3 and I’m currently supporting earlier versions. I can’t just migrate to v2 and drop support for older IDEs in a patch release. Besides, moving to v2 is a lot of work and adds more complexity to the build.

I also used PluginDescriptor.getPluginPath() a lot. Without a PluginDescriptor, there are new methods in PluginPathManager, but because there’s no migration etc. a separate build is required to use them.

Edit: I’m also using PluginManagerCore.disablePlugin() to disable a plugin after the user confirmed it in UI. The JavaDoc just says “don’t use it”, but mentions no alternative API or a replacement. How can I disable a plugin, with or without any further interaction by the user?

If I’m missing something obvious, I’d be glad to know.

Thanks!

I have to admit I’m using reflection in order to access the good old PluginManager.
I will migrate to PluginDetailsService in a year or two, not before.

Also, I’m still not sure to understand why it has been moved to Internal. If my understanding is correct, this is for security reasons, but we (legit but, unfortunately, also malicious) users can still access it via reflection ^_^.

I can assure you all plugins with .getPlugin(PluginId) : IdeaPluginDescriptor usages will continue publishing automatically till 2026.3 at least, even though local verification fails already. We will enforce it only once we have full one Major release covered

We have a plan to remove methods at some point completely, as they no longer part of API surface

We are working on a permission manager API that will let you suggest plugin management actions to users for their approval. No new usages of disablePlugin are allowed at this time, though all existing usages in currently shipped plugins are approved.

Our position is that plugins may not manage other plugins directly. Given the current security landscape, we cannot permit such error-prone and potentially suspicious practices.

In the future you should never interact with it as it is our implementation detail

We can provide that timely in PluginDetails, thanks for noticing

Yeah, that’s a challenge. I built a plugin as a replacement for another plugin, but having both plugins installed will lead to surprising results, and [incomptible-with] will just make it impossible to install my plugin, while the incompatibility is a bidirectional challenge.

Can’t there be an approval process, even as part of the disablePlugin method, where the user has to give explicit consent? (I built this myself now, and removed it, cause my plugin doesn’t pass the verifier)

Hi, did you try <incompatible-with> in plugin.xml? This way the platform handles the plugin conflict.

Example from C++ support that is not compatible with Kotlin Multiplatform

<incompatible-with>com.jetbrains.kmm</incompatible-with>

Yeah, I did, but it just prevents my plugin from being installed, that’s not a good solution.

Sorry, I wrote it in my original post, but the forum filtered it out.

My current approach will most likely be that I’ll allow the incompatible plugin to be installed, and then present a popup telling the user to disable the other plugin manually, I don’t really see better options at the moment, but I think this if what “disablePlugin” should do:

Plugin X wants to disable plugin Y because reason Z, are you okay with that yes/no

Could you describe the case a bit more? How is that your plugin incompatible with the other? Is it a built-in plugin in an IDE?

Hi Yuriy, thanks for your response. In this case it actually is, but I’m not sure if it matters much. The plugin in question is my Vue Pro plugin, which conflicts with the bundled Vue plugin which has several issues. So I wrote a version which is slightly better. However, it is triggered by .vue files, just like the Jetbrains version of the plugin, and it would be hard to have 2 plugins be used for the same filetype. If I declare my plugin incompatible with the bundled Vue plugin, which is what I have done now, it will be quite hard to install it, which goes against what I’m trying to accomplish here. So, I was aiming for a solution which shows a popup, with user input to disable the built-in version of the Jetbrains plugin.

But this is just an example, there are, for example, also multiple plugins for Solidity. Having multiple plugins for the same filetype would again be a potentially bad experience, since who is handling the .sol file?

So, this is the challenge I have, and I was hoping to use the disablePlugin feature for this, but my latest version of the plugin doesn’t pass the verifier, so not sure what the best way to proceed is, except for what I described earlier: allow two competing plugins to be installed, and direct the user to manually disable the other plugin, which, to me, doesn’t sound like a great UX.

It’s unfortunate that your plugin needs to disable our built-in functionality. In this situation, users inevitably lose access to our features in order to use your plugin, which isn’t an ideal experience.

I think a better outcome for users would be to integrate with the existing functionality rather than duplicate its behavior. As far as I know, the WebStorm team is generally open to adding extension points or improving the platform to make it more robust and interoperable with other plugins.

I think you’re getting distracted by the example I gave you, that’s really not the point here.

I can give a different example and the point would be the same; there’s scenarios where plugins solve the same problem, which will conflict with each other, and the focus of this conversation was how to solve that, not if making a better version of the Vue plugin is a good idea or not.

Yes, that is why I mentioned Permission Manager we have in plans some messages above, which will let you do suggestions to users about disabling some plugins, but not manage them directly

Perhaps it would be an idea to keep the existing APIs, including the disablePlugin logic for existing plugins until the new Permission Manager is there? Plugin builders don’t have a solution right now to disable plugins.

All current usages were approved manually so far, but yes, no new usages are allowed, as we don’t want to have new such cases incoming till then. You may still suggest users disabling plugins by simply opening Plugin settings via

ShowSettingsUtil.getInstance().showSettingsDialog(
  project,
  PluginManagerConfigurable.class
);

Thanks, that’s the goal indeed.