apache/maven · error · PluginExecutionException
An API incompatibility was encountered while executing ${moj
Error message
An API incompatibility was encountered while executing ${mojoDescriptor.getId()}: ${e.getClass().getName()}: ${e.getMessage()} What it means
A LinkageError other than NoClassDefFoundError (typically NoSuchMethodError, AbstractMethodError, IllegalAccessError or IncompatibleClassChangeError) escaped a mojo execution. The plugin was compiled against one version of an API but the plugin realm supplies another: the classes exist, but their method signatures or access modifiers no longer match. Maven dumps the realm and rethrows everything as PluginContainerException inside PluginExecutionException.
Source
Thrown at impl/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java:186
mojoExecutionListener.afterExecutionFailure(
new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println(
"A required class was missing while executing " + mojoDescriptor.getId() + ": " + e.getMessage());
pluginRealm.display(ps);
Exception wrapper = new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), e);
throw new PluginExecutionException(mojoExecution, project, wrapper);
} catch (LinkageError e) {
mojoExecutionListener.afterExecutionFailure(
new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println("An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
+ e.getClass().getName() + ": " + e.getMessage());
pluginRealm.display(ps);
Exception wrapper = new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), e);
throw new PluginExecutionException(mojoExecution, project, wrapper);
} catch (ClassCastException e) {
mojoExecutionListener.afterExecutionFailure(
new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(os);
ps.println("A type incompatibility occurred while executing " + mojoDescriptor.getId() + ": "
+ e.getMessage());
pluginRealm.display(ps);
throw new PluginExecutionException(mojoExecution, project, os.toString(), e);
} catch (RuntimeException e) {
mojoExecutionListener.afterExecutionFailure(
new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
throw e;
} finally {
mavenPluginManager.releaseMojo(mojo, mojoExecution);
scope.exit();
Thread.currentThread().setContextClassLoader(oldClassLoader);
legacySupport.setSession(oldSession);View on GitHub (pinned to e4093d4e12)
Solutions
- Take the incompatible class and method from the LinkageError message, then scan the dumped plugin realm for two artifacts with the same groupId:artifactId at different versions.
- Pin the version the plugin expects in the plugin's <dependencies> so only one version lands in the realm.
- Upgrade the plugin to a release built against the API version present in your build.
- If the clash is with an API provided by Maven core itself, move to a plugin release compatible with your Maven version.
Example fix
<!-- before: plugin release built for an older Maven line --> <plugin> <artifactId>some-plugin</artifactId> <version>1.2</version> </plugin> <!-- after: use the release built for your Maven version --> <plugin> <artifactId>some-plugin</artifactId> <version>2.3</version> </plugin>
Defensive patterns
Strategy: validation
Validate before calling
mvn -Dmaven.plugin.validation=VERBOSE validate 2>&1 | tee /tmp/plugin-validation.log grep -E 'incompatible|duplicate|excluded' /tmp/plugin-validation.log
Try / catch
catch (PluginExecutionException e) {
Throwable c = e;
while (c.getCause() != null && !(c instanceof LinkageError)) c = c.getCause();
if (c instanceof LinkageError le) {
// le.getMessage() names the expected class/method: fix the realm, do not retry
log.error("binary incompatibility: {}", le.getMessage());
}
throw e;
} Prevention
- Upgrade plugins together with Maven upgrades, not independently
- Check mvn dependency:tree output for duplicate groupId:artifactId pairs on plugin classpaths
- Enable -Dmaven.plugin.validation=VERBOSE in CI to catch API-level mismatches before execution
When it happens
Trigger: The plugin realm resolves a different version of a library than the one the plugin was compiled against, so a resolved method signature is missing or an abstract method is unimplemented. Classic cases: two versions of the same groupId:artifactId on the plugin classpath, or a plugin built against a newer Maven/plexus API than the running Maven provides.
Common situations: Upgrading Maven while keeping old plugin versions that need newer plexus/sisu APIs; dependency convergence failures pulling an older transitive version into the realm; libraries that changed signatures between minor versions.
Related errors
- A required class was missing while executing {}: {}
- Unable to load the mojo '${mojoDescriptor.getGoal()}' in the
- Unable to load the mojo '${mojoDescriptor.getGoal()}' in the
- A required class was missing during configuration of mojo ${
- An API incompatibility was encountered during configuration
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/a8b3be093b9751ce.
Report an issue: GitHub.