mybatis/mybatis-3 · error · BuilderException
If there is no type discriminator, then the NamedResultMap a
Error message
If there is no type discriminator, then the NamedResultMap annotation requires at least one constructor argument or property mapping
What it means
Thrown by MapperAnnotationBuilder.validateNamedResultMap(): a @NamedResultMap annotation declares neither a type discriminator nor any constructorArguments() nor propertyMappings(). Without at least one mapping (or a discriminator to route types), the named result map would carry no column-to-property information and is rejected as a configuration error.
Source
Thrown at src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java:266
String resultMapId = type.getName() + '.' + namedResultMap.id();
Class<?> returnType = namedResultMap.javaType();
Arg[] args = namedResultMap.constructorArguments();
Result[] results = namedResultMap.propertyMappings();
TypeDiscriminator typeDiscriminator = namedResultMap.typeDiscriminator();
if (AnnotationConstants.NULL_TYPE_DISCRIMINATOR.equals(typeDiscriminator.column())) {
typeDiscriminator = null;
}
applyResultMap(resultMapId, returnType, args, results, typeDiscriminator);
}
private void validateNamedResultMap(NamedResultMap namedResultMap) {
if (!AnnotationConstants.NULL_TYPE_DISCRIMINATOR.equals(namedResultMap.typeDiscriminator().column())) {
return;
}
if (namedResultMap.constructorArguments().length == 0 && namedResultMap.propertyMappings().length == 0) {
throw new BuilderException("If there is no type discriminator, then the NamedResultMap annotation "
+ "requires at least one constructor argument or property mapping");
}
}
private String generateResultMapName(Method method) {
Results results = method.getAnnotation(Results.class);
if (results != null && !results.id().isEmpty()) {
return type.getName() + "." + results.id();
}
StringBuilder suffix = new StringBuilder();
for (Class<?> c : method.getParameterTypes()) {
suffix.append("-");
suffix.append(c.getSimpleName());
}
if (suffix.length() < 1) {
suffix.append("-void");
}
return type.getName() + "." + method.getName() + suffix;View on GitHub (pinned to 008069adb1)
Solutions
- Add at least one @Arg in constructorArguments or @Property in propertyMappings to the @NamedResultMap
- Or add a typeDiscriminator so the map routes among subtypes
- If you only wanted automapping by resultType, drop @NamedResultMap entirely and use resultType on the statement
Example fix
// before @NamedResultMap(id = "userMap") // after @NamedResultMap(id = "userMap", propertyMappings = @Property(column = "user_name", property = "userName"))
Defensive patterns
Strategy: validation
Validate before calling
for (Method m : mapper.getMethods()) {
NamedResultMap nrm = m.getAnnotation(NamedResultMap.class);
if (nrm != null && nrm.constructorArguments().length == 0
&& nrm.propertyMappings().length == 0
&& "@null@".equals(nrm.typeDiscriminator().column())) { /* default sentinel */
throw new IllegalStateException(m + " has empty @NamedResultMap");
}
} Prevention
- Only add @NamedResultMap when mappings are ready; otherwise use resultType automapping
- Add a config-load test that instantiates all mapper annotations in CI
When it happens
Trigger: @NamedResultMap(id = "userMap") with empty constructorArguments, propertyMappings, and typeDiscriminator defaulting to the NULL discriminator column.
Common situations: Adding @NamedResultMap intending to reuse it via @ResultMap before filling in mappings; misunderstanding that the annotation requires explicit mappings (unlike automapping); leftover stub annotation after removing mappings.
Related errors
- Error in result map '{resultMapId}'. We do not support parti
- Should be specified either value() or name() attribute in th
- Cannot use both value() and name() attribute in the @CacheNa
- Cannot use both @One and @Many annotations in the same @Resu
- A query was run and no Result Maps were found for the Mapped
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/93e1323b1715cce0.
Report an issue: GitHub.