mybatis/mybatis-3 · error · BuilderException
Error evaluating expression '" + expression + "'. Cause: " +
Error message
Error evaluating expression '" + expression + "'. Cause: " + e
What it means
OgnlCache.getValue() wraps any OGNL runtime failure in a BuilderException whose message embeds the failing expression and the original OgnlException. This is the generic failure point for every OGNL evaluation MyBatis performs: test="..." conditions in <if>/<when>, and ${...} string substitutions. The cause chain is preserved, so the root reason (syntax error, missing property, null navigation, wrong method signature) is in the nested exception.
Source
Thrown at src/main/java/org/apache/ibatis/scripting/xmltags/OgnlCache.java:49
*
* @see <a href='https://github.com/mybatis/old-google-code-issues/issues/342'>Issue 342</a>
*/
public final class OgnlCache {
private static final OgnlMemberAccess MEMBER_ACCESS = new OgnlMemberAccess();
private static final OgnlClassResolver CLASS_RESOLVER = new OgnlClassResolver();
private static final Map<String, Object> expressionCache = new ConcurrentHashMap<>();
private OgnlCache() {
// Prevent Instantiation of Static Class
}
public static Object getValue(String expression, Object root) {
try {
OgnlContext context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null);
return Ognl.getValue(parseExpression(expression), context, root);
} catch (OgnlException e) {
throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
}
}
private static Object parseExpression(String expression) throws OgnlException {
Object node = expressionCache.get(expression);
if (node == null) {
node = Ognl.parseExpression(expression);
expressionCache.put(expression, node);
}
return node;
}
}
View on GitHub (pinned to 008069adb1)
Solutions
- Read the nested Cause in the stack trace: it names the exact property/method OGNL could not resolve.
- Align the property path in test= or ${} with the actual parameter (check @Param annotations on the mapper method).
- For null-safety, guard navigation: test="user != null and user.name != null".
- Add the missing getter or @Param to the parameter object.
Example fix
// before
<if test="name != null">AND name = #{name}</if>
<!-- mapper: find(@Param('userName') String name) -->
// after
<if test="userName != null">AND name = #{userName}</if> Defensive patterns
Strategy: try-catch
Try / catch
try { return sqlSession.selectList(stmt, param); }
catch (BuilderException e) {
Throwable root = e.getCause(); // OgnlException with the real reason
log.error("OGNL failed for {}: {}", stmt, root.getMessage());
throw e;
} Prevention
- Keep @Param names and XML test=/${} expressions in one review unit when changing either side.
- Null-guard navigation in tests: 'a != null and a.b != null'.
- Write one smoke test per mapper method so OGNL regressions surface in CI, not production.
When it happens
Trigger: A test="usr.name != null" where the parameter has no getName(); OGNL syntax errors like test="a == && b"; calling a method that does not exist in test="list.size() > 0" when the property is not a list; navigating into a null intermediate object with an invalid path; using ${} with a property name that is absent from the parameter map.
Common situations: Renaming a Java field/getter without updating mapper XML; copy-pasting an <if test> from another statement with a different parameter name; @Param name mismatch between mapper interface and XML; upgrading MyBatis/OGNL versions where grammar got stricter; null parameter passed to a dynamic statement.
Related errors
- Error evaluating expression '" + expression + "'. Return va
- The expression '" + expression + "' evaluated to a null valu
- Parsing error was found in mapping #{{content}}. Check synt
- There is no getter for property named '{}' in '{}'
- Invalid index syntax in property: '{}'. Missing closing brac
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/a25b17bc0c18c764.
Report an issue: GitHub.