NoClassDefFoundError during component initialisation Follow
Since upgrading to 2016.3, several users have reported the following error at startup:
Plugin 'com.cursiveclojure.cursive' failed to initialize and will be disabled. Please restart IntelliJ IDEA. java.lang.NoClassDefFoundError: Could not initialize class clojure.lang.RT at cursive.config.InitComponent.initClojure(InitComponent.java:100) at cursive.config.InitComponent.initComponent(InitComponent.java:78) at com.intellij.openapi.components.impl.ComponentManagerImpl$ComponentConfigComponentAdapter.getComponentInstance(ComponentManagerImpl.java:501) at com.intellij.openapi.components.impl.ComponentManagerImpl.createComponents(ComponentManagerImpl.java:125) at com.intellij.openapi.application.impl.ApplicationImpl.lambda$createComponents$8(ApplicationImpl.java:441) at com.intellij.openapi.progress.impl.CoreProgressManager$3.run(CoreProgressManager.java:179) at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:568) at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:519) at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:54) at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:164) at com.intellij.openapi.application.impl.ApplicationImpl.createComponents(ApplicationImpl.java:448) at com.intellij.openapi.components.impl.ComponentManagerImpl.init(ComponentManagerImpl.java:109) at com.intellij.openapi.application.impl.ApplicationImpl.load(ApplicationImpl.java:400) at com.intellij.openapi.application.impl.ApplicationImpl.load(ApplicationImpl.java:386) at com.intellij.idea.IdeaApplication.run(IdeaApplication.java:190) at com.intellij.idea.MainImpl$1.lambda$null$0(MainImpl.java:47) ...etc etc...
This class is definitely available in the plugin. I've checked the layout of their installed plugin, and the jar containing that class is available in the correct location. What could cause this error? What else should I get them to check?
Please sign in to leave a comment.
could you please provide the full stacktrace? It looks like there may be some 'caused by' clauses.
No, there don't seem to be:
BTW here's the original issue, with a bit of extra detail. I got one user to check that the unpacked layout of his plugin looks ok and that the jar containing that class is present, which it is.
This is a critical issue for me, my plugin is commercial and right now several users can't use it because of this issue. Any help would be much appreciated.
'NoClassDefFoundError: Could not initialize class' doesn't mean that JVM cannot find the class. It happens if a program tries to access a class which was failed to initialize when it was accessed for the first time. Most probably it means that some of static initializers of clojure.lang.RT failed with exception, so when some code tried to access it for a first time it failed with ExceptionInInitializerError, and all subsequent accesses fail with 'NoClassDefFoundError: Could not initialize class'.
So in order to find the cause we need to get the stacktrace of the original ExceptionInInitializerError. If it wasn't ignored it should be printed in idea.log.
I see, thanks for the information. I'll get the full logs from the users.
I now have a full log - there are no other exceptions in the log between the IDE STARTED and IDE SHUTDOWN lines. Here's the full stacktrace:
I cannot see anywhere obvious in this class's static initialiser which swallows an exception. The class is huge and does a lot of static init, but it all seems to rethrow the exception.
I got one of the affected users to use the Java agent from here: http://eiie-logger.kohsuke.org, but he still sees no EIIE in his logs. This seems to be a race condition of some kind - users have reported that the problem is sometimes fixed by installing the Scala plugin, and one reported that uninstalling the Scala plugin provoked the problem. However this doesn't work for everyone, at least one user experiences the problem and it is not resolved by installing Scala.
As far as I can see clojure classes aren't used in IntelliJ platform and our bundled plugins, so the problem seems to be caused by a plugin's code. You can try searching for all usages of clojure classes in your code and check that there are no empty catch clauses around these calls.
Actually, IntelliJ does bundle clojure-1.8.0 (you can see it in the app's lib dir). However I believe that PluginClassLoader should always load my copy before the platform one. That said, clearly something has changed in 2016.3 which is provoking this problem (even if it is a problem in my plugin's code, which I'm sure it is). It may just be some subtlety in the component initialisation order - I've had similar problems before.
After some debugging with the help of a friendly user who could reproduce this issue, I've figured this out. This is due to a CompletionContributor defined in Clojure code being invoked earlier than previously by the CompletionPreloader, which seems to be new in 2016.3. For whatever reason, for some users this would happen before my ApplicationComponent which initialises Clojure, and this would cause an EIIE which was not logged. Here's the stacktrace:
I've gone through the stacktrace, and the logging issue seems to be in the BoundedTaskExecutor.wrapAndExecute() code:
The comments claim that these exceptions will be stored in the FutureTask somehow, but I cannot see how this would happen. Is this expected?
The CompletionPreloader also seems to break what I had thought was an invariant - I had assumed that language-specific extensions (ones declared with "language='Clojure'" in plugin.xml) would not be loaded until the functionality of that language was required. Is that assumption false, or is this a bug?
thank you for investigating this! Regarding ignored exceptions: this code looks strange for me too, I've asked its author about it.
In general language-specific extensions points are indeed loaded only if the corresponding language is used in the project. However you shouldn't rely on it. E.g. if your CompletionProvider depends on some other component/service, you need to make this dependency explicit by adding class of that component/service as a parameter to the CompletionProvider's constructor. This way you'll ensure that instance of that component/service will be created before the CompletionProvider initializes.