mybatis/mybatis-3 · error · BuilderException

Expression based parameters are not supported yet

Error message

Expression based parameters are not supported yet

What it means

Thrown by ParameterMappingTokenHandler when a #{} placeholder contains an 'expression=...' option. MyBatis once planned OGNL-based parameter expressions inside placeholders but never shipped support; the option is recognized by the parser (to give a precise message) yet explicitly unsupported and rejected.

Source

Thrown at src/main/java/org/apache/ibatis/builder/ParameterMappingTokenHandler.java:119

      typeHandler = resolveTypeHandler(genericType, jdbcType, typeHandlerAlias);
    }
    builder.typeHandler(typeHandler);

    ParameterMode mode = null;
    for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
      String name = entry.getKey();
      String value = entry.getValue();
      if ("mode".equals(name)) {
        mode = resolveParameterMode(value);
        builder.mode(mode);
      } else if ("numericScale".equals(name)) {
        builder.numericScale(Integer.valueOf(value));
      } else if ("resultMap".equals(name)) {
        builder.resultMapId(value);
      } else if ("jdbcTypeName".equals(name)) {
        builder.jdbcTypeName(value);
      } else if ("expression".equals(name)) {
        throw new BuilderException("Expression based parameters are not supported yet");
      } else {
        throw new BuilderException("An invalid property '" + name + "' was found in mapping #{" + content
            + "}.  Valid properties are " + PARAMETER_PROPERTIES);
      }
    }
    if (!ParameterMode.OUT.equals(mode) && paramExists) {
      if (metaParameters.hasGetter(propertyTokenizer.getName())) {
        builder.value(metaParameters.getValue(property));
      } else if (parameterObject == null) {
        builder.value(null);
      } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
        builder.value(parameterObject);
      } else {
        MetaObject metaObject = configuration.newMetaObject(parameterObject);
        builder.value(metaObject.getValue(property));
      }
    }
    return builder.build();

View on GitHub (pinned to 008069adb1)

Solutions

  1. Remove the expression option and compute the value in Java before passing the parameter
  2. Use <if>/<choose>/<foreach> dynamic SQL (or @SelectProvider / Provider SQL builder) for conditional logic
  3. For static trusted text, ${} substitution can be used with full SQL-injection caution

Example fix

<!-- before -->
#{user,expression=name.toUpperCase()}
<!-- after -->
query.setName(user.getName().toUpperCase());
... WHERE name = #{name}
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast if generated SQL contains the unsupported expression option
if (sql.contains("expression=")) {
  throw new UnsupportedOperationException("#{...,expression=...} is not supported by MyBatis");
}

Prevention

When it happens

Trigger: Writing #{user,expression=id > 100} or any placeholder option list containing expression=... in an XML mapper or annotation SQL.

Common situations: Developers attempt dynamic per-row expressions in a batch or try to inline computed values; occasionally copied from very old MyBatis 2.x / iBATIS examples where similar syntax existed.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/9ede439249317948. Report an issue: GitHub.