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()}'. A required class is missing: ${cause.getMessage()}

What it means

Maven built the plugin's class realm but could not load the mojo class because a class it references is absent from that realm. DefaultMavenPluginManager walks the cause chain to the first NoClassDefFoundError/ClassNotFoundException and throws PluginContainerException, appending a dump of every jar/URL in the plugin realm so you can see which artifact should have supplied the missing class. The class name after 'A required class is missing:' is the key diagnostic.

Source

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

        T mojo;

        try {
            mojo = container.lookup(mojoInterface, mojoDescriptor.getRoleHint());
        } catch (ComponentLookupException e) {
            Throwable cause = e.getCause();
            while (cause != null && !(cause instanceof LinkageError) && !(cause instanceof ClassNotFoundException)) {
                cause = cause.getCause();
            }

            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);

View on GitHub (pinned to e4093d4e12)

Solutions

  1. Read the realm dump in the message: find the class named after 'A required class is missing:' and check which artifact in the dump (or missing from it) should contain it.
  2. Delete the suspect artifact directory under ~/.m2/repository and rebuild with mvn -U so it is re-downloaded and checksum-verified.
  3. Remove or narrow <exclusions> declared on the plugin (or its parent pluginManagement) so the required transitive jar returns to the realm.
  4. Pin the correct version of the missing library under <plugin><dependencies> if another plugin dependency pulls an incompatible subset.
  5. Upgrade or downgrade the plugin to a version whose dependency set resolves cleanly in your environment.

Example fix

// before: blanket exclusion strips a jar the mojo needs
<plugin>
  <groupId>org.example</groupId>
  <artifactId>example-maven-plugin</artifactId>
  <version>1.2.0</version>
  <dependencies>
    <dependency>
      <groupId>org.example</groupId>
      <artifactId>example-spi</artifactId>
      <version>1.4.0</version>
      <exclusions>
        <exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</plugin>

// after: drop the wildcard exclusion so the missing class is back on the plugin classpath
<plugin>
  <groupId>org.example</groupId>
  <artifactId>example-maven-plugin</artifactId>
  <version>1.2.0</version>
</plugin>
Defensive patterns

Strategy: try-catch

Validate before calling

# pre-flight: force full plugin resolution and drop zero-byte stubs before the real build
mvn -B dependency:resolve-plugins
find ~/.m2/repository -name '*.jar' -size -1b -print -delete
mvn -U verify

Type guard

static boolean missingClassInMojoRealm(PluginContainerException e) {
    Throwable c = e.getCause();
    return c instanceof NoClassDefFoundError || c instanceof ClassNotFoundException;
}

Try / catch

try {
    Object mojo = pluginManager.getConfiguredMojo(mojoDescriptor, pluginRealm, session, mojoExecution);
} catch (PluginContainerException e) {
    Throwable c = e.getCause();
    if (c instanceof NoClassDefFoundError || c instanceof ClassNotFoundException) {
        // classpath hole: e.getMessage() already embeds the plugin realm dump
        reportPluginClasspathHole(e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling mojo execution (direct goal invocation, lifecycle phase, or embedder getConfiguredMojo) when the plugin realm lacks a jar: a blanket <exclusions> on the plugin or its dependency, dependency mediation dropping a transitive jar, an optional/provided dependency that is not present, or a corrupted/zero-byte jar in the local repository.

Common situations: Copy-pasted <exclusions> with groupId/artifactId wildcards in pluginManagement; interrupted downloads leaving broken jars in ~/.m2/repository; running with -o (offline) against a partially cached plugin; plugin version expecting a library that a pinned older dependency shadows.

Related errors


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