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

  1. 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.
  2. Pin the version the plugin expects in the plugin's <dependencies> so only one version lands in the realm.
  3. Upgrade the plugin to a release built against the API version present in your build.
  4. 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

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


AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21). Data as JSON: /api/errors/a8b3be093b9751ce. Report an issue: GitHub.