Legacy Knowledge Base
Published Sep. 10, 2025

java.lang.UnsatisfiedLinkError: Native Library xxxx already loaded in another classloader after redeploying

Written By

Jorge Diaz

How To articles are not official guidelines or officially supported documentation. They are community-contributed content and may not always reflect the latest updates to Liferay DXP. We welcome your feedback to improve How To articles!

While we make every effort to ensure this Knowledge Base is accurate, it may not always reflect the most recent updates or official guidelines.We appreciate your understanding and encourage you to reach out with any feedback or concerns.

Legacy Article

You are viewing an article from our legacy "FastTrack" publication program, made available for informational purposes. Articles in this program were published without a requirement for independent editing or verification and are provided"as is" without guarantee.

Before using any information from this article, independently verify its suitability for your situation and project.

Issue

In our custom developments, we are using a Jar library that uses an external native loaded using JNI.

When we deploy our custom development in a clean environment everything works fine, but if we redeploy it, following error is thrown:

java.lang.UnsatisfiedLinkError: Native Library xxxx already loaded in another classloader
at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2456)
at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2649)

Restarting the application server solves the problem until the next development redeploy.

 

Environment

  • Liferay DXP 7.0-7.4

Resolution

The error is caused by the way the OSGI framework works when a module is stopped and restarted. In these cases, what OSGI does is create a new classloader where it reloads all the classes of the module, so at any given moment there may be a class loaded by different classloaders:

  • the one corresponding to the one used by the module before stopping it
  • and the one corresponding to the module after starting it again.

The old classloader is completely removed from memory once there are no longer any memory references to any classes loaded by it and the garbage collection is executed.
 
This can cause problems if the library is not OSGI-ready, for example, if it has static variables or uses native operating system libraries. In those cases, there may be references that are not released correctly.
 
On the other hand, in the specific case of native libraries, there is a restriction imposed by the JVM in which they cannot be loaded more than once by different classloaders, see https://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#library_version 

In the JDK, each class loader manages its own set of native libraries. The same JNI native library cannot be loaded into more than one class loader. Doing so causes UnsatisfiedLinkError to be thrown. For example, System.loadLibrary throws an UnsatisfiedLinkError when used to load a native library into two class loaders

 
Therefore, for these cases of JARs that use native library loading through JNI, it would not be possible to load the JAR through OSGI without errors occurring if the module that includes the library is restarted individually. It would also not be possible for you to have multiple OSGI modules trying to load the same library.
 

Workaround using module.framework.system.packages.extra property

 
There is a workaround to load JAR libraries globally to the entire OSGI framework that consists of adding the JAR to the Liferay libraries folder and then configuring the OSGI framework to expose the packages of this JAR to the modules that make use of it.

This workaround should only be used if there is no other alternative and as long as the library does not collide with any package of any java class that Liferay comes with as standard.
 
In order to load the library globally, you would have to follow these steps, with the Liferay server stopped:

  1. Copy the problematic JAR into the folder:
    • DXP 7.0-7.3: [LIFERAY_HOME]/tomcat-9.x.x/webapps/ROOT/WEB-INF/lib
    • DXP 7.4: [LIFERAY_HOME]/tomcat-9.x.x/webapps/ROOT/WEB-INF/shielded-container-lib
  2. Go to the portal-impl.jar file and get from it the portal.properties file from which you have to copy the module.framework.system.packages.extra section that will be similar to https://github.com/liferay/liferay-portal/blob/7.4.3.24-ga24/portal-impl/src/portal.properties#L7349-L7381 (note: this snippet may change with each new Liferay DXP product update that is released, so you will need to review it on each update)
  3. Copy the  module.framework.system.packages.extra section to your portal-ext.propertiesfile
  4. Add at the end of the section separated by commas the library packages that you have copied to lib / shielded-container-lib

 
This approach allows the classes of the library will be available for all the OSGI modules that need them.
 
For more information check the following article: Resolving ClassNotFoundException and NoClassDefFoundError in OSGi Bundles - The Missing Class Belongs to a Global Library 
 
Finally, indicate that in the OSGI module that makes use of the JAR in question, you will have to declare the dependency with said package ("compileOnly" type dependencies only at compile time) if the module does not have said dependency declared, it will not have access to the classes in question.

 

Additional Information

 

 

Did this article resolve your issue ?

Legacy Knowledge Base