How to fix: Why is Maven JAR Plugin writing *.jar contents into the *.pom file?
🚨 Understanding the Error
Section titled “🚨 Understanding the Error”In a standard Maven build lifecycle, the maven-jar-plugin is responsible for packaging compiled .class files and resources into a .jar (Java Archive). Separately, Maven generates a .pom file which acts as the Project Object Model XML descriptor.
When you see binary data (often starting with the hex signature 50 4B 03 04 or the string PK - the ZIP file header) inside a file named your-artifact.pom, it indicates a collision in the build output stream. The Maven session has essentially been misconfigured to treat the POM’s destination path as the output target for the JAR binary. This results in an unreadable POM file, causing failures during the install or deploy phases because the repository manager cannot parse the XML metadata.
🔍 Root Cause
Section titled “🔍 Root Cause”| Cause | Technical Description |
|---|---|
Misconfigured <outputFile> |
Explicitly overriding the maven-jar-plugin output path to a string ending in .pom. |
| Shade Plugin Conflict | The maven-shade-plugin with createDependencyReducedPom set to true, pointing to the same location as the JAR output. |
| Artifact Attachment Hijacking | A custom plugin or maven-antrun-plugin task manually renaming the binary artifact to the POM filename. |
| Property Collision | Using a property like ${project.build.finalName} in a way that forces the JAR to overwrite the POM descriptor during the package phase. |
🛠️ Step-by-Step Solutions
Section titled “🛠️ Step-by-Step Solutions”1. Audit the maven-jar-plugin Configuration
Section titled “1. Audit the maven-jar-plugin Configuration”The most common cause is an accidental path override. Ensure you are not forcing the plugin to write to a .pom extension.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.3.1</version> <configuration> <!-- BAD: Forcing the output to a POM path --> <!-- <outputDirectory>${project.build.directory}/classes</outputDirectory> --> <!-- <finalName>${project.artifactId}.pom</finalName> -->
<!-- GOOD: Let Maven handle the extension --> <classifier>bin</classifier> </configuration></plugin>2. Inspect the maven-shade-plugin Logic
Section titled “2. Inspect the maven-shade-plugin Logic”If you are creating an “uber-jar,” the Shade plugin generates a dependency-reduced-pom.xml. If the dependencyReducedPomLocation is misconfigured, it can cause file system contention.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <!-- Ensure this isn't pointing to your primary artifact path --> <createDependencyReducedPom>true</createDependencyReducedPom> <dependencyReducedPomLocation> ${project.build.directory}/dependency-reduced-pom.xml </dependencyReducedPomLocation> </configuration> </execution> </executions></plugin>3. Debug via Effective POM
Section titled “3. Debug via Effective POM”Hidden configurations in parent POMs or active profiles might be overriding your defaults. Run the following command to see the merged XML:
mvn help:effective-pom -Doutput=effective-pom.xml
Search the generated effective-pom.xml for any instances of <extension>pom</extension> inside a plugin configuration that handles binary packaging.
4. Fix Lifecycle Overlap
Section titled “4. Fix Lifecycle Overlap”If you are using the maven-antrun-plugin to move files, ensure you aren’t overwriting the POM.
<!-- Example of what to avoid in antrun --><tasks> <move file="${project.build.directory}/${project.build.finalName}.jar" tofile="${project.build.directory}/${project.build.finalName}.pom" /> <!-- CRITICAL ERROR --></tasks>🛡️ Prevention and Best Practices
Section titled “🛡️ Prevention and Best Practices”- Stick to Conventions: Avoid overriding
${project.build.directory}or${project.build.finalName}unless absolutely necessary. Maven’s “Convention over Configuration” exists to prevent exactly this type of IO collision. - Use Classifiers: If you need to produce multiple JARs, use
<classifier>(e.g.,sources,javadoc,shaded) instead of changing the file extension or base name. - Validate Artifacts: Before running
mvn deploy, always runmvn clean packageand inspect thetargetfolder. - Plugin Version Management: Use the
<pluginManagement>section in your parent POM to lock plugin versions, preventing “rogue” behavior from older, buggy versions of packaging plugins. - Verify POM Integrity: Use cat target/*.pom | head -n 5 to ensure the file starts with
<?xml version="1.0" ...and not binary garbage.