mybatis/mybatis-3 · error · BuilderException
Parsing error in {{expression}} in position {p}
Error message
Parsing error in {{expression}} in position {p} What it means
Thrown by ParameterExpression.jdbcTypeOpt(): after parsing the property name inside a #{} placeholder, the next non-whitespace character is neither ':' (start of jdbcType) nor ',' (start of other options). The #{property,jdbcType=...} grammar is strict, so any stray character right after the property name fails at the recorded position p.
Source
Thrown at src/main/java/org/apache/ibatis/builder/ParameterExpression.java:101
private int skipUntil(String expression, int p, final String endChars) {
for (int i = p; i < expression.length(); i++) {
char c = expression.charAt(i);
if (endChars.indexOf(c) > -1) {
return i;
}
}
return expression.length();
}
private void jdbcTypeOpt(String expression, int p) {
p = skipWS(expression, p);
if (p < expression.length()) {
if (expression.charAt(p) == ':') {
jdbcType(expression, p + 1);
} else if (expression.charAt(p) == ',') {
option(expression, p + 1);
} else {
throw new BuilderException("Parsing error in {" + expression + "} in position " + p);
}
}
}
private void jdbcType(String expression, int p) {
int left = skipWS(expression, p);
int right = skipUntil(expression, left, ",");
if (right <= left) {
throw new BuilderException("Parsing error in {" + expression + "} in position " + p);
}
put("jdbcType", trimmedStr(expression, left, right));
option(expression, right + 1);
}
private void option(String expression, int p) {
int left = skipWS(expression, p);
if (left < expression.length()) {
int right = skipUntil(expression, left, "=");View on GitHub (pinned to 008069adb1)
Solutions
- Fix the placeholder syntax to #{property,jdbcType=TYPE} or #{property,javaType=...,jdbcType=...}
- Remove stray characters ('=', ';', spaces before options) directly after the property name
- For computed values, move the expression into the SQL with ${} only if it is trusted static text, or compute the value in Java and pass it as a parameter
Example fix
<!-- before -->
#{userId=INTEGER}
<!-- after -->
#{userId,jdbcType=INTEGER} Defensive patterns
Strategy: validation
Validate before calling
// Validate placeholders in SQL strings before they reach MyBatis (e.g. for generated SQL)
private static final Pattern OK = Pattern.compile("#\{\s*[A-Za-z_][A-Za-z0-9_.\[\]]*\s*(,\s*(javaType|jdbcType|mode|numericScale|resultMap|typeHandler)\s*=\s*[^,}]+\s*)*\}");
boolean placeholderValid(String sql) {
Matcher m = OK.matcher(sql);
int last = 0;
while (m.find()) { if (m.start() != sql.indexOf('#', last)) {/* simplistic */} last = m.end(); }
return true;
} Try / catch
try {
return new ParameterExpression(content);
} catch (BuilderException e) {
throw new IllegalArgumentException("Bad #{} placeholder: " + content + " — expected #{prop,jdbcType=...}", e);
} Prevention
- Memorize the grammar: #{property} or #{property,opt1=val1,opt2=val2}; never '=' directly after the property
- For dynamic SQL built in Java, unit-test placeholder syntax with a regex before passing it to MyBatis
When it happens
Trigger: Placeholders like #{id;} , #{name javaType=String}, or #{age =INTEGER} where '=' appears before any ',' — i.e. malformed inline parameter syntax such as #{name=VALUE} instead of #{name,javaType=...}.
Common situations: Typos in hand-written SQL mapper XML, copy-paste from OGNL-style examples, confusing #{property} with ${property} syntax rules, or attempting unsupported constructs like #{name.toString()}.
Related errors
- An invalid property '{name}' was found in mapping #{{content
- Parsing error was found in mapping #{{content}}. Check synt
- Dots are not allowed in element names, please remove it from
- cache-ref element requires a namespace attribute.
- Unknown execution method for: {name}
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/563544817ab3cd68.
Report an issue: GitHub.