apache/maven · error · XMLStreamException

Duplicated tag: '${rootTag}'

Error message

Duplicated tag: '${rootTag}'

What it means

Identical to the modern template's guard: after one root element has been parsed, the read loop continues to END_DOCUMENT, and a second top-level START_ELEMENT triggers this duplicate-root fallback. Well-formed XML cannot have two roots, so this surfaces mainly with lenient/custom STAX parsers or concatenated-document streams that present the second root as an event.

Source

Thrown at src/mdo/reader.vm:445

     *
     * @param parser a parser object.
     * @param strict a strict object.
     * @throws IOException IOException if any.
     * @throws XMLStreamException XMLStreamException if
     * any.
     * @return ${root.name}
     */
    public ${root.name} read(XMLStreamReader parser, boolean strict) throws IOException, XMLStreamException {
        $rootUcapName $rootLcapName = null;
        int eventType = parser.getEventType();
        boolean parsed = false;
        while (eventType != XMLStreamReader.END_DOCUMENT) {
            if (eventType == XMLStreamReader.START_ELEMENT) {
                if (strict && ! "${rootTag}".equals(parser.getLocalName())) {
                    throw new XMLStreamException("Expected root element '${rootTag}' but found '" + parser.getLocalName() + "'", parser.getLocation(), null);
                } else if (parsed) {
                    // fallback, already expected a XMLStreamException due to invalid XML
                    throw new XMLStreamException("Duplicated tag: '${rootTag}'", parser.getLocation(), null);
                }
                $rootLcapName = parse${rootUcapName}(parser, strict);
                parsed = true;
            }
            eventType = parser.next();
        }
        if (parsed) {
            return $rootLcapName;
        }
        throw new XMLStreamException("Expected root element '${rootTag}' but found no element at all: invalid XML document", parser.getLocation(), null);
    } //-- ${root.name} read(XMLStreamReader, boolean)

#foreach ( $class in $model.allClasses )
 #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
  #set ( $classUcapName = $Helper.capitalise( $class.name ) )
  #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
  #set ( $ancestors = $Helper.ancestors( $class ) )
  #set ( $allFields = [] )

View on GitHub (pinned to e4093d4e12)

Solutions

  1. Make the input a single well-formed document - wrap or split the content.
  2. Split concatenated documents on each <?xml declaration and parse each with its own reader.
  3. Pre-validate with a standard STAX parser to fail early on multi-root input.

Example fix

// before: one InputStream holding two concatenated pom documents
reader.read(in, true); // throws Duplicated tag: 'project'

// after: split documents, parse each separately
for (byte[] doc : splitXmlDocuments(in)) {
    Model model = reader.read(new ByteArrayInputStream(doc), true);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-scan: a standard factory itself rejects a second root during next()
XMLInputFactory f = XMLInputFactory.newFactory();
f.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader p = f.createXMLStreamReader(new ByteArrayInputStream(bytes));
try {
    while (p.hasNext()) { p.next(); } // throws on the second top-level element
} finally {
    p.close();
}

Try / catch

try {
    Model model = reader.read(parser, true);
} catch (XMLStreamException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Duplicated tag")) {
        // multiple top-level elements in the stream: fix the producer
    }
    throw e;
}

Prevention

When it happens

Trigger: read() over a stream with two concatenated XML documents; lenient XMLStreamReader implementations that do not enforce single-root well-formedness; strict=false reads where a second top-level element follows the first parsed root.

Common situations: Test fixtures joining several XML snippets; CI outputs flushing multiple documents into one stream; appended/truncated files repaired by concatenation.

Related errors


AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21). Data as JSON: /api/errors/212800c756258e08. Report an issue: GitHub.