mybatis/mybatis-3 · error · BuilderException
Unknown element <" + nodeName + "> in SQL statement.
Error message
Unknown element <" + nodeName + "> in SQL statement.
What it means
XMLScriptBuilder parses the body of a statement mapped to XMLLanguageDriver and only recognizes MyBatis' own dynamic SQL tags (if, choose, when, otherwise, trim, where, set, foreach, bind) plus text. When a child element's node name has no registered NodeHandler, this BuilderException is thrown at configuration/mapper-parsing time. It almost always means a misspelled or non-MyBatis XML element inside a SELECT/INSERT/UPDATE/DELETE (or sql fragment) block.
Source
Thrown at src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java:108
XNode child = node.newXNode(children.item(i));
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
String data = child.getStringBody("");
if (data.trim().isEmpty()) {
contents.add(emptyNodeCache.computeIfAbsent(data, EmptySqlNode::new));
continue;
}
TextSqlNode textSqlNode = new TextSqlNode(data);
if (textSqlNode.isDynamic()) {
contents.add(textSqlNode);
isDynamic = true;
} else {
contents.add(new StaticTextSqlNode(data));
}
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
String nodeName = child.getNode().getNodeName();
NodeHandler handler = nodeHandlerMap.get(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
handler.handleNode(child, contents);
isDynamic = true;
}
}
return new MixedSqlNode(contents);
}
private interface NodeHandler {
void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
}
private static class BindHandler implements NodeHandler {
public BindHandler() {
// Prevent Synthetic Access
}
@OverrideView on GitHub (pinned to 008069adb1)
Solutions
- Open the mapper XML named in the stack trace and fix the element shown in <...> to one of: if, choose, when, otherwise, trim, where, set, foreach, bind.
- Remove non-MyBatis/JSTL tags from statement bodies; move that logic into OGNL test expressions or provider-based SQL.
- Re-run and let the parser confirm the next error until the file is clean (it fails fast on the first bad element).
Example fix
// before
<select id="find" resultMap="r">
SELECT * FROM t
<wher><if test="id != null">id = #{id}</if></wher>
</select>
// after
<select id="find" resultMap="r">
SELECT * FROM t
<where><if test="id != null">id = #{id}</if></where>
</select> Defensive patterns
Strategy: validation
Validate before calling
// Fast-fail at startup: parse all mappers eagerly SqlSessionFactory f = new SqlSessionFactoryBuilder().build(cfgXml); // parsing happens at build(); any unknown element throws here, before serving traffic
Try / catch
try { factory = builder.build(in); }
catch (BuilderException e) { /* fail startup with mapper file + element name */ throw e; } Prevention
- Build the SqlSessionFactory once at application startup so XML errors fail fast.
- Enable XML schema/DTD validation in the IDE for mapper files.
- Restrict dynamic tags to the known set: if, choose/when/otherwise, trim, where, set, foreach, bind.
When it happens
Trigger: A typo such as <wher>, <ifo>, <foreache> inside a statement body; using JSTL or custom tags like <c:if> inside MyBatis XML; a stray namespace prefix element; nesting a <select> or other top-level mapper element inside a statement body by mistake.
Common situations: Hand-editing mapper XML and misspelling a dynamic tag; copy-pasting from a JSP/JSTL template; XML IDE auto-completing the wrong tag; editing an included <sql> fragment with an element type not valid there.
Related errors
- Too many default (otherwise) elements in choose statement.
- Error evaluating XPath. Cause: {}
- Error creating document instance. Cause: {}
- Error evaluating expression '" + expression + "'. Return va
- Error evaluating expression '" + expression + "'. Cause: " +
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/6f45dfe70ba89208.
Report an issue: GitHub.