apache/maven · error · DuplicateMojoDescriptorException
Goal: {goal} already exists in the plugin descriptor for pre
Error message
Goal: {goal} already exists in the plugin descriptor for prefix: {goalPrefix}
Existing implementation is: {existingImplementation}
Conflicting implementation is: {newImplementation} What it means
PluginDescriptor.addMojoDescriptor identifies mojos by role:roleHint, i.e. goalPrefix:goal. Adding a second MojoDescriptor with the same goal under the same prefix throws DuplicateMojoDescriptorException, reporting both the existing and the conflicting implementation classes.
Source
Thrown at compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java:177
public List<MojoDescriptor> getMojos() {
return (List) getComponents();
}
public void addMojo(MojoDescriptor mojoDescriptor) throws DuplicateMojoDescriptorException {
MojoDescriptor existing = null;
// this relies heavily on the equals() and hashCode() for ComponentDescriptor,
// which uses role:roleHint for identity...and roleHint == goalPrefix:goal.
// role does not vary for Mojos.
List<MojoDescriptor> mojos = getMojos();
if (mojos != null && mojos.contains(mojoDescriptor)) {
int indexOf = mojos.indexOf(mojoDescriptor);
existing = mojos.get(indexOf);
}
if (existing != null) {
throw new DuplicateMojoDescriptorException(
getGoalPrefix(),
mojoDescriptor.getGoal(),
existing.getImplementation(),
mojoDescriptor.getImplementation());
} else {
addComponentDescriptor(mojoDescriptor);
}
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getArtifactId() {View on GitHub (pinned to e4093d4e12)
Solutions
- Give each mojo a unique goal name (@Mojo(name = ...) or plugin.xml <goal>)
- Remove the stale duplicate class or plugin.xml entry
- If both mojos are legitimately needed, move one to a different plugin so the goalPrefix differs
- Regenerate the descriptor with maven-plugin-tools after any goal renames
Example fix
// before: two mojos, same goal name -> DuplicateMojoDescriptorException
@Mojo(name = "run") public class RunMojo extends AbstractMojo {}
@Mojo(name = "run") public class ExecMojo extends AbstractMojo {}
// after: unique goal per mojo under one goalPrefix
@Mojo(name = "run") public class RunMojo extends AbstractMojo {}
@Mojo(name = "exec") public class ExecMojo extends AbstractMojo {} Defensive patterns
Strategy: validation
Validate before calling
// Guard programmatic descriptor assembly
if (pluginDescriptor.getMojo(mojoDescriptor.getGoal()) != null) {
throw new IllegalArgumentException(
"Goal already present: " + pluginDescriptor.getGoalPrefix() + ":" + mojoDescriptor.getGoal());
}
pluginDescriptor.addMojoDescriptor(mojoDescriptor); Type guard
static boolean goalExists(PluginDescriptor pd, String goal) {
return pd.getMojo(goal) != null;
} Prevention
- Keep one @Mojo class per goal name per plugin
- Regenerate plugin.xml after renaming goals
- When merging plugins, check goalPrefix:goal pairs for collisions first
When it happens
Trigger: Two mojos in one plugin declaring the same goal name: two @Mojo(name = "run") classes, duplicate <goal> entries in plugin.xml, or repeated programmatic addMojoDescriptor calls.
Common situations: Splitting or copying a mojo class without changing @Mojo name; hand-edited plugin.xml; descriptor merging in tests or build tooling.
Related errors
- {parameterName} has been declared multiple times in mojo wit
- Two or more projects in the reactor have the same identifier
- Unable to load plugin lifecycles
- Project '{}' is duplicated in the reactor
- path, url, reader or inputStream must be non null
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/4789a66ce7dcda54.
Report an issue: GitHub.