baomidou/mybatis-plus · error · BuilderException

Unknown element <%s> in SQL statement.

Error message

Unknown element <%s> in SQL statement.

What it means

While parsing a mixed dynamic SQL node, MybatisXMLScriptBuilder encountered an element child that is not one of the supported node handlers (trim, where, set, foreach, if, choose, when, otherwise, bind). Any other tag inside a SQL statement is rejected at parse time.

Source

Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisXMLScriptBuilder.java:171

            if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
                String text = cacheStr(child.getStringBody(""));
                if (text.trim().isEmpty()) {
                    StaticTextSqlNode staticTextSqlNode = CACHE_EMPTY_SQL_NODE.computeIfAbsent(text, StaticTextSqlNode::new);
                    contents.add(staticTextSqlNode);
                    continue;
                }
                TextSqlNode textSqlNode = new TextSqlNode(text);
                if (textSqlNode.isDynamic()) {
                    contents.add(textSqlNode);
                    isDynamic = true;
                } else {
                    contents.add(new StaticTextSqlNode(text));
                }
            } 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 class BindHandler implements NodeHandler {
        public BindHandler() {
            // Prevent Synthetic Access
        }

        @Override

View on GitHub (pinned to bf67d90747)

Solutions

  1. Remove or rename the offending element named in the message to a supported one (if/choose/foreach/where/set/trim/bind)
  2. If the tag is reusable SQL text, move it into a <sql id="..."> fragment and reference it with <include refid="..."/>
  3. If the tag was a typo of a supported element, correct the tag name

Example fix

<!-- before -->
<select id="list" resultType="User">
  <columns>id, name</columns> FROM user
</select>
<!-- after -->
<sql id="userCols">id, name</sql>
<select id="list" resultType="User">
  SELECT <include refid="userCols"/> FROM user
</select>
Defensive patterns

Strategy: validation

Validate before calling

// During build, assert only whitelisted dynamic-SQL tags appear inside statements:
Set<String> OK = Set.of("if","choose","when","otherwise","trim","where","set","foreach","bind","include","sql");
NodeList kids = stmtElement.getChildNodes();
for (int i = 0; i < kids.getLength(); i++) {
    Node n = kids.item(i);
    if (n.getNodeType() == Node.ELEMENT_NODE && !OK.contains(n.getNodeName()))
        throw new IllegalStateException("Unsupported tag <" + n.getNodeName() + "> in " + stmtElement.getAttribute("id"));
}

Prevention

When it happens

Trigger: Placing a custom or mistaken element inside <select>/<update> SQL, e.g. <column>, <sql> include misuse, a stray HTML tag pasted in, or a typo like <iffe> instead of <if>; also custom tags intended for other templating engines left in the mapper XML.

Common situations: Copy-pasting SQL from documentation/HTML that carries formatting tags; dialect-specific XML fragments; a custom tag from a homegrown preprocessor that is no longer run.

Related errors


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/360d2ab854e68ce1. Report an issue: GitHub.