mybatis/mybatis-3 · error · ExecutorException
Expected result object to be a pending constructor creation!
Error message
Expected result object to be a pending constructor creation!
What it means
Internal invariant of collection constructor injection: when the resultMap uses constructor-based collection mapping (hasResultMapsUsingConstructorCollection), getRowValue must return a PendingConstructorCreation placeholder so the handler can defer building the object until all child rows are seen. If the row value is not that placeholder type, MyBatis cannot proceed and throws this ExecutorException — it indicates an inconsistent mapping configuration, not user data.
Source
Thrown at src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java:410
+ "or ensure your statement returns ordered data and set resultOrdered=true on it.");
}
}
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
final boolean useCollectionConstructorInjection = resultMap.hasResultMapsUsingConstructorCollection();
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
skipRows(resultSet, rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw, resultMap, null);
Object rowValue = getRowValue(rsw, discriminatedResultMap, null, null);
if (!useCollectionConstructorInjection) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
} else {
if (!(rowValue instanceof PendingConstructorCreation)) {
throw new ExecutorException("Expected result object to be a pending constructor creation!");
}
createAndStorePendingCreation(resultHandler, resultSet, resultContext, (PendingConstructorCreation) rowValue);
}
}
}
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue,
ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
return;
}
if (pendingPccRelations.containsKey(rowValue)) {
createPendingConstructorCreations(rowValue);
}
View on GitHub (pinned to 008069adb1)
Solutions
- Make the resultMap consistent: map collection constructor args entirely through <constructor><arg javaType='...list-type...' resultMap='nested'/> and do not mix them with automapped collection properties
- Simplify to classic property-based <collection> mapping (no constructor arg collection) and remove the constructor-collection setup
- If it reproduces on valid mappings, report a bug to MyBatis with the resultMap XML and result classes
Example fix
<!-- before: mixed styles -> inconsistent internal state --> <resultMap id="orderMap" type="Order"> <constructor><arg column="id" javaType="long"/></constructor> <collection property="items" ofType="Item"/> <!-- property collection alongside ctor flags --> </resultMap> <!-- after: single style --> <resultMap id="orderMap" type="Order"> <id property="id" column="id"/> <collection property="items" ofType="Item"/> </resultMap>
Defensive patterns
Strategy: validation
Validate before calling
// Keep mappings single-style: either constructor-collection or property collections
ResultMap rm = session.getConfiguration().getResultMap("orderMap");
if (rm.hasResultMapsUsingConstructorCollection() && rm.getResultMappings().stream().anyMatch(m -> m.getNestedResultMapId() != null && m.getProperty() != null)) {
log.warn("Mixed constructor-collection and property collection mapping in {}", rm.getId());
} Prevention
- Avoid mixing <constructor><arg> collection mappings with <collection> property mappings in one resultMap
- Test each resultMap against representative rows in CI
- Report reproducible cases upstream with full mapping XML
When it happens
Trigger: handleRowValuesForSimpleResultMap iterates rows on a resultMap where hasResultMapsUsingConstructorCollection() is true, but getRowValue returned null or a fully built object instead of PendingConstructorCreation — typically a mixing of constructor-arg collection mapping with plain property automapping in the same resultMap.
Common situations: A resultMap that declares <constructor><arg> referencing a nested collection in some branches while a discriminator or automapping path returns a normal instance; custom ResultMap builds via ResultMap.Builder that set the constructor-collection flag inconsistently; edge-case mappings after upgrading MyBatis.
Related errors
- Error getting constructor collection nested result map value
- Error in result map '{resultMapId}'. Failed to find a constr
- Error in result map '{resultMapId}'. We do not support parti
- Mapped Statements with nested result mappings cannot be safe
- Mapped Statements with nested result mappings cannot be safe
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/90e59a0e70ec9ea0.
Report an issue: GitHub.