apache/maven · error · PluginContainerException

Unable to load the mojo '${mojoDescriptor.getGoal()}' in the

Error message

Unable to load the mojo '${mojoDescriptor.getGoal()}' in the plugin '${pluginDescriptor.getId()}' due to an API incompatibility: ${e.getClass().getName()}: ${cause.getMessage()}

What it means

The mojo failed to load with a LinkageError that is not a missing class: NoSuchMethodError, NoSuchFieldError, AbstractMethodError, IllegalAccessError, VerifyError, and similar. The classes exist in the plugin realm but are binary-incompatible with what the plugin was compiled against, so DefaultMavenPluginManager throws PluginContainerException including the original error class, its message, and a dump of the plugin realm. This is almost always a wrong library version on the plugin classpath, not a code bug in your build.

Source

Thrown at impl/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java:717

            if ((cause instanceof NoClassDefFoundError) || (cause instanceof ClassNotFoundException)) {
                ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
                PrintStream ps = new PrintStream(os);
                ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
                        + pluginDescriptor.getId() + "'. A required class is missing: "
                        + cause.getMessage());
                pluginRealm.display(ps);

                throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
            } else if (cause instanceof LinkageError) {
                ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
                PrintStream ps = new PrintStream(os);
                ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
                        + pluginDescriptor.getId() + "' due to an API incompatibility: "
                        + e.getClass().getName() + ": " + cause.getMessage());
                pluginRealm.display(ps);

                throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
            }

            throw new PluginContainerException(
                    mojoDescriptor,
                    pluginRealm,
                    "Unable to load the mojo '" + mojoDescriptor.getGoal()
                            + "' (or one of its required components) from the plugin '"
                            + pluginDescriptor.getId() + "'",
                    e);
        }

        if (mojo instanceof ContextEnabled contextEnabledMojo) {
            MavenProject project = session.getCurrentProject();

            Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);

            if (pluginContext != null) {
                pluginContext.put("project", project);

View on GitHub (pinned to e4093d4e12)

Solutions

  1. Read the message: the error class (e.g. NoSuchMethodError) names the missing member and its declaring class; search the realm dump for which artifact currently supplies that class.
  2. Pin the version the plugin expects under <plugin><dependencies> so the realm resolves the compatible build.
  3. Upgrade the plugin to a version aligned with the rest of your dependency stack.
  4. Run mvn -X (debug) to see the exact realm composition and mediation decisions if the dump is ambiguous.
  5. If the error mentions a JDK-internal class, move Maven itself onto the JDK the plugin requires.

Example fix

// before: mediation pulls guava 19.0 into the realm, plugin compiled against 32.x -> NoSuchMethodError
// after: pin the matching version inside the plugin block
<plugin>
  <groupId>org.example</groupId>
  <artifactId>example-maven-plugin</artifactId>
  <version>1.0.0</version>
  <dependencies>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>32.1.3-jre</version>
    </dependency>
  </dependencies>
</plugin>
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-flight: dump the resolved plugin classpath and look for unexpected versions of conflict-prone libraries
mvn -X dependency:resolve-plugins 2>&1 | grep -E 'guava|commons-|asm' | sort -u

Type guard

static boolean binaryIncompatibleMojo(PluginContainerException e) {
    Throwable c = e.getCause();
    return c instanceof LinkageError && !(c instanceof NoClassDefFoundError);
}

Try / catch

try {
    Object mojo = pluginManager.getConfiguredMojo(mojoDescriptor, pluginRealm, session, mojoExecution);
} catch (PluginContainerException e) {
    if (e.getCause() instanceof LinkageError le && !(le instanceof NoClassDefFoundError)) {
        // NoSuchMethodError/NoSuchFieldError/... : pin the conflicting library inside <plugin><dependencies>
        reportVersionConflict(le);
    }
    throw e;
}

Prevention

When it happens

Trigger: Dependency mediation inside the plugin realm selects an older/newer version of a library (Guava, commons-*, ASM, SLF4J) than the plugin requires; a library duplicated across plugin dependencies; plugin compiled against a JDK API not present in the JDK running Maven.

Common situations: Two plugins (or a plugin and its dependency) forcing different versions of the same library; upgrading one plugin while pinning a shared dependency; running a modern plugin on an EOL JDK; shaded plugins with duplicate classes.

Related errors


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