mybatis/mybatis-3 · error · IllegalArgumentException
ResultMaps must have an id
Error message
ResultMaps must have an id
What it means
ResultMap.Builder.build() throws IllegalArgumentException when the resultMap being constructed has a null id. Every ResultMap must be identifiable (usually its namespace-qualified name) because statements, nested mappings and Discriminators reference result maps by id.
Source
Thrown at src/main/java/org/apache/ibatis/mapping/ResultMap.java:91
resultMap.configuration = configuration;
resultMap.id = id;
resultMap.type = type;
resultMap.resultMappings = resultMappings;
resultMap.autoMapping = autoMapping;
}
public Builder discriminator(Discriminator discriminator) {
resultMap.discriminator = discriminator;
return this;
}
public Class<?> type() {
return resultMap.type;
}
public ResultMap build() {
if (resultMap.id == null) {
throw new IllegalArgumentException("ResultMaps must have an id");
}
resultMap.mappedColumns = new HashSet<>();
resultMap.mappedProperties = new HashSet<>();
resultMap.idResultMappings = new ArrayList<>();
resultMap.constructorResultMappings = new ArrayList<>();
resultMap.propertyResultMappings = new ArrayList<>();
for (ResultMapping resultMapping : resultMap.resultMappings) {
resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null;
resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || resultMapping.getNestedResultMapId() != null
&& resultMapping.getResultSet() == null && !JdbcType.CURSOR.equals(resultMapping.getJdbcType());
final String column = resultMapping.getColumn();
if (column != null) {
resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
} else if (resultMapping.isCompositeResult()) {
for (ResultMapping compositeResultMapping : resultMapping.getComposites()) {
final String compositeColumn = compositeResultMapping.getColumn();View on GitHub (pinned to 008069adb1)
Solutions
- Pass a non-null, unique id: new ResultMap.Builder(config, "com.example.UserResult", User.class, mappings).build().
- When generating dynamically, derive the id from class + mapping hash to keep it stable and unique.
- Register the built ResultMap under the same id in Configuration.addResultMap so references resolve.
Example fix
// before ResultMap rm = new ResultMap.Builder(config, null, User.class, mappings).build(); // after ResultMap rm = new ResultMap.Builder(config, "com.example.mapper.UserMapper.UserResult", User.class, mappings).build();
Defensive patterns
Strategy: validation
Validate before calling
// Generate a stable unique id when building ResultMaps dynamically String id = User.class.getName() + "#" + Integer.toHexString(mappings.hashCode()); ResultMap rm = new ResultMap.Builder(config, id, User.class, mappings).build();
Prevention
- Never pass null as the ResultMap id; derive it from the mapped type plus a discriminator.
- Register built ResultMaps via configuration.addResultMap(rm) under the same id so references resolve.
- Prefer XML <resultMap> where ids are generated automatically, unless dynamic mapping is required.
When it happens
Trigger: Programmatically building ResultMap without new ResultMap.Builder(configuration, null).with... — i.e. passing a null id; XML <resultMap> always generates an id, so this is almost exclusive to Java-built configurations and custom language drivers.
Common situations: Constructing ResultMaps dynamically (e.g. for dynamic schemas in generic frameworks) and forgetting to generate a unique id; utility code that copies ResultMaps but drops the id; third-party plugins built against older APIs.
Related errors
- Parameter 'id' must not be null
- Parameter 'transactionFactory' must not be null
- Parameter 'dataSource' must not be null
- Cannot define both nestedQueryId and nestedResultMapId in pr
- dataSource cannot be null
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/2e310953c94793af.
Report an issue: GitHub.