apache/maven · error · XmlPullParserException
Duplicated tag: 'extensions'
Error message
Duplicated tag: 'extensions'
What it means
CoreExtensionsXpp3Reader is the generated XML pull-parser for .mvn/extensions.xml. In strict mode it accepts exactly one root <extensions> element; after the first root has been parsed, encountering another START_TAG named 'extensions' at document level throws XmlPullParserException 'Duplicated tag: extensions'. In practice this means the file contains two concatenated root elements — malformed XML with more than one document root.
Source
Thrown at compat/maven-embedder/src/main/java/org/apache/maven/cli/internal/extension/model/io/xpp3/CoreExtensionsXpp3Reader.java:516
* @param parser a parser object.
* @param strict a strict object.
* @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return CoreExtensions
*/
public CoreExtensions read(XmlPullParser parser, boolean strict) throws IOException, XmlPullParserException {
CoreExtensions coreExtensions = null;
int eventType = parser.getEventType();
boolean parsed = false;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (strict && !"extensions".equals(parser.getName())) {
throw new XmlPullParserException(
"Expected root element 'extensions' but found '" + parser.getName() + "'", parser, null);
} else if (parsed) {
// fallback, already expected a XmlPullParserException due to invalid XML
throw new XmlPullParserException("Duplicated tag: 'extensions'", parser, null);
}
coreExtensions = parseCoreExtensions(parser, strict);
coreExtensions.setModelEncoding(parser.getInputEncoding());
parsed = true;
}
eventType = parser.next();
}
if (parsed) {
return coreExtensions;
}
throw new XmlPullParserException(
"Expected root element 'extensions' but found no element at all: invalid XML document", parser, null);
} // -- CoreExtensions read( XmlPullParser, boolean )
/**
* @see XmlStreamReader
*
* @param reader a reader object.View on GitHub (pinned to e4093d4e12)
Solutions
- Open .mvn/extensions.xml and merge everything into a single root: one <extensions> element containing all <extension> children.
- Validate the file as XML (xmllint --noout .mvn/extensions.xml) — any XML parser flags the double root immediately.
- Fix the generating script to write atomically (overwrite) rather than append.
- Re-run mvn to confirm the extension loads (optionally -X for detail).
Example fix
<!-- before (.mvn/extensions.xml): two roots --> <extensions> <extension>...</extension> </extensions> <extensions> <extension>...</extension> </extensions> <!-- after: single merged root --> <extensions> <extension>...</extension> <extension>...</extension> </extensions>
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight XML sanity check for .mvn/extensions.xml
var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
factory.setValidating(false);
var doc = factory.newDocumentBuilder().parse(file); // throws on double root / malformed XML
if (!"extensions".equals(doc.getDocumentElement().getTagName())) {
throw new IllegalStateException("Root element must be <extensions>");
} Try / catch
try {
cli.doMain(args, workingDir, ...);
} catch (org.codehaus.plexus.util.xml.pull.XmlPullParserException e) {
if ("Duplicated tag: 'extensions'".equals(e.getMessage())) {
// merge the concatenated roots into one and retry
}
throw e;
} Prevention
- Run xmllint --noout .mvn/extensions.xml in CI lint; a double root is caught by any XML parser.
- Generate extensions.xml atomically (write temp + move), never append with cat >>.
- Resolve merge conflicts by merging <extension> entries, never by keeping both root elements.
When it happens
Trigger: A .mvn/extensions.xml produced by concatenating two files (e.g. a template merge or double-append in a script), or manual editing that duplicated the <extensions>...</extensions> block. Copy-pasting a second extensions block below the first instead of merging entries.
Common situations: CI scripts that append extension entries with 'cat >>' and run twice, duplicating the whole root element. Editors/plugins auto-inserting a fresh skeleton below existing content. Merge conflicts resolved by keeping both sides' root elements.
Related errors
- Expected root element 'extensions' but found no element at a
- Cannot read toolchains file at " + userToolchainsFile.getAbs
- Unsupported class-loading strategy '{}'. Supported values ar
- Extension {} or one of its dependencies could not be resolve
- Cannot read metadata from '{}': {}
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/eacccf2128d43d49.
Report an issue: GitHub.