mybatis/mybatis-3 · error · BuilderException

An invalid property '{name}' was found in mapping #{{content

Error message

An invalid property '{name}' was found in mapping #{{content}}.  Valid properties are {PARAMETER_PROPERTIES}

What it means

Thrown when a #{} placeholder option list contains a property name outside the allowed set. The valid set (PARAMETER_PROPERTIES) is javaType, jdbcType, mode, numericScale, resultMap, typeHandler, jdbcTypeName (per ParameterMapping). Unrecognized names (e.g. 'type', 'value', 'nullable') are rejected with this message listing the valid names.

Source

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

    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. Use one of the valid option names: javaType, jdbcType, mode, numericScale, resultType? (resultMap for OUT params), typeHandler
  2. Check the exact spelling in the error message's PARAMETER_PROPERTIES list it prints
  3. Remove options that are not needed — plain #{property} is usually correct

Example fix

<!-- before -->
#{id,type=INTEGER}
<!-- after -->
#{id,jdbcType=INTEGER}
Defensive patterns

Strategy: validation

Validate before calling

private static final Set<String> VALID = Set.of("javaType","jdbcType","mode","numericScale","resultMap","typeHandler");

void checkPlaceholderOptions(String content) {
  Map<String,String> opts = new ParameterExpression(content);
  for (String k : opts.keySet()) {
    if (!VALID.contains(k)) throw new IllegalArgumentException("Invalid #{} option '" + k + "' in " + content);
  }
}

Try / catch

try {
  new ParameterExpression(content);
} catch (BuilderException e) {
  if (e.getMessage().contains("Valid properties are")) {
    // surface allowed list to the developer
    throw new IllegalArgumentException("Bad placeholder options: " + content, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Writing #{id,type=INTEGER} instead of #{id,jdbcType=INTEGER}, or #{id,nullable=true} — any option key not in ParameterMapping's PARAMETER_PROPERTIES constant.

Common situations: Guessing option names ('type' instead of 'jdbcType'), copy-paste from JPA/NamedParameterJdbcTemplate style syntax, or typos like 'jdbcTyp'.

Related errors


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