{"record":{"id":"4789a66ce7dcda54","repo":"apache/maven","slug":"goal-goal-already-exists-in-the-plugin-descript","errorCode":null,"errorMessage":"Goal: {goal} already exists in the plugin descriptor for prefix: {goalPrefix}\nExisting implementation is: {existingImplementation}\nConflicting implementation is: {newImplementation}","messagePattern":"Goal: (.+?) already exists in the plugin descriptor for prefix: (.+?)\nExisting implementation is: (.+?)\nConflicting implementation is: (.+?)","errorType":"exception","errorClass":"DuplicateMojoDescriptorException","httpStatus":null,"severity":"error","filePath":"compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java","lineNumber":177,"sourceCode":"    public List<MojoDescriptor> getMojos() {\n        return (List) getComponents();\n    }\n\n    public void addMojo(MojoDescriptor mojoDescriptor) throws DuplicateMojoDescriptorException {\n        MojoDescriptor existing = null;\n        // this relies heavily on the equals() and hashCode() for ComponentDescriptor,\n        // which uses role:roleHint for identity...and roleHint == goalPrefix:goal.\n        // role does not vary for Mojos.\n        List<MojoDescriptor> mojos = getMojos();\n\n        if (mojos != null && mojos.contains(mojoDescriptor)) {\n            int indexOf = mojos.indexOf(mojoDescriptor);\n\n            existing = mojos.get(indexOf);\n        }\n\n        if (existing != null) {\n            throw new DuplicateMojoDescriptorException(\n                    getGoalPrefix(),\n                    mojoDescriptor.getGoal(),\n                    existing.getImplementation(),\n                    mojoDescriptor.getImplementation());\n        } else {\n            addComponentDescriptor(mojoDescriptor);\n        }\n    }\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getArtifactId() {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java#L159-L195","documentation":"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.","triggerScenarios":"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.","commonSituations":"Splitting or copying a mojo class without changing @Mojo name; hand-edited plugin.xml; descriptor merging in tests or build tooling.","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"],"exampleFix":"// before: two mojos, same goal name -> DuplicateMojoDescriptorException\n@Mojo(name = \"run\") public class RunMojo extends AbstractMojo {}\n@Mojo(name = \"run\") public class ExecMojo extends AbstractMojo {}\n\n// after: unique goal per mojo under one goalPrefix\n@Mojo(name = \"run\") public class RunMojo extends AbstractMojo {}\n@Mojo(name = \"exec\") public class ExecMojo extends AbstractMojo {}","handlingStrategy":"validation","validationCode":"// Guard programmatic descriptor assembly\nif (pluginDescriptor.getMojo(mojoDescriptor.getGoal()) != null) {\n    throw new IllegalArgumentException(\n        \"Goal already present: \" + pluginDescriptor.getGoalPrefix() + \":\" + mojoDescriptor.getGoal());\n}\npluginDescriptor.addMojoDescriptor(mojoDescriptor);","typeGuard":"static boolean goalExists(PluginDescriptor pd, String goal) {\n    return pd.getMojo(goal) != null;\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["maven","plugin-descriptor","duplicate","mojo-goal"],"backgroundTag":"duplicate-declaration","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}