{"record":{"id":"d65959cf509fb403","repo":"gradle/gradle","slug":"pom-file-is-invalid-check-any-modifications-you-h","errorCode":null,"errorMessage":"POM file is invalid. Check any modifications you have made to the POM file.","messagePattern":"POM file is invalid\\. Check any modifications you have made to the POM file\\.","errorType":"exception","errorClass":"InvalidMavenPublicationException","httpStatus":null,"severity":"error","filePath":"platforms/software/maven/src/main/java/org/gradle/api/publish/maven/internal/publisher/ValidatingMavenPublisher.java","lineNumber":80,"sourceCode":"                .validMavenIdentifier();\n        MavenFieldValidator versionValidator = field(publication, \"version\", publication.getVersion())\n                .notEmpty()\n                .validInFileName();\n\n        if (!hasParentPom) {\n            groupIdValidator.matches(model.getGroupId());\n            versionValidator.matches(model.getVersion());\n        }\n    }\n\n    private Model parsePomFileIntoMavenModel(MavenNormalizedPublication publication) {\n        File pomFile = publication.getPomArtifact().getFile();\n        try {\n            Model model = readModelFromPom(pomFile);\n            model.setPomFile(pomFile);\n            return model;\n        } catch (XmlPullParserException parseException) {\n            throw new InvalidMavenPublicationException(publication.getName(),\n                    \"POM file is invalid. Check any modifications you have made to the POM file.\",\n                    parseException);\n        } catch (IOException ex) {\n            throw UncheckedException.throwAsUncheckedException(ex);\n        }\n    }\n\n    @SuppressWarnings(\"DefaultCharset\")\n    private Model readModelFromPom(File pomFile) throws IOException, XmlPullParserException {\n        // Note: source files can have non-UTF8 encoding. FileReader uses default Charset and also handles invalid characters.\n        try (FileReader reader = new FileReader(pomFile)) {\n            return new MavenXpp3Reader().read(reader);\n        }\n    }\n\n    private void validateArtifacts(MavenNormalizedPublication publication) {\n        for (MavenArtifact artifact : publication.getAllArtifacts()) {\n            field(publication, \"artifact extension\", artifact.getExtension())","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/gradle/gradle/blob/534f27719b66953f95cc907aae7f2c1b12f5482d/platforms/software/maven/src/main/java/org/gradle/api/publish/maven/internal/publisher/ValidatingMavenPublisher.java#L62-L98","documentation":"ValidatingMavenPublisher re-parses the generated POM with Maven's Xpp3 reader before upload. An XmlPullParserException means the POM file is not well-formed XML, so the publication is aborted with InvalidMavenPublicationException.","triggerScenarios":"pom.withXml injecting raw strings with unescaped & or < characters; manually editing the generated pom-default.xml under build/publications/ between generation and publish; tools or plugins corrupting the generated file.","commonSituations":"withXml blocks using asString().append(...) with free text containing & or <; developers hand-patching generated POMs instead of the DSL; encoding problems in injected text.","solutions":["Build XML with the node API (asNode().appendNode(...)) instead of appending raw strings","Escape injected text (&, <, >) or set values via the node API, then clean and regenerate: ./gradlew clean generatePomFileForMavenPublication","Never hand-edit files under build/publications - treat them as outputs and rerun the generator"],"exampleFix":"// before\npom.withXml { asString().append('<description>AT&T tools</description>') } // unescaped &\n\n// after\npom.withXml {\n    def root = asNode()\n    if (root.description.isEmpty()) root.appendNode('description')\n    root.description[0].value = 'AT&T tools'\n}","handlingStrategy":"validation","validationCode":"import groovy.xml.XmlSlurper\ntasks.withType(GenerateMavenPom).configureEach {\n    doLast {\n        new XmlSlurper().parse(outputFile) // throws immediately if the POM is not well-formed\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new XmlSlurper().parse(pomFile)\n} catch (org.xml.sax.SAXException e) {\n    // fix the withXml block that injects raw text; escape & and <\n}","preventionTips":["Generate XML via the node API (asNode().appendNode) rather than string concatenation","Escape free text injected through withXml","Never hand-edit generated POMs under build/publications - rerun generatePomFile instead"],"tags":["gradle","maven","publishing","pom","xml-parsing"],"backgroundTag":"malformed-pom-xml","analyzedSha":"534f27719b66953f95cc907aae7f2c1b12f5482d","analyzedAt":"2026-08-22T08:09:12.375Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}