mybatis/mybatis-3 · error · ExecutorException
Cannot reliably construct result if we are not sure the resu
Error message
Cannot reliably construct result if we are not sure the results are ordered so that no new previous rows would occur, set resultOrdered on your mapped statement if you have verified this
What it means
When MyBatis defers object creation for constructor-mapped collections (pending creations), it must be sure rows arrive grouped so it has seen every child before building the parent. That guarantee only exists when the mapped statement is marked resultOrdered="true". Without it, an earlier row for an already-emitted parent could arrive later and be lost or corrupt the grouping, so the engine refuses to proceed.
Source
Thrown at src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java:1385
// create the pending objects
for (Object pendingCreation : pendingCreations) {
if (pendingCreation instanceof PendingConstructorCreation) {
final PendingConstructorCreation pendingConstructorCreation = (PendingConstructorCreation) pendingCreation;
targetMetaObject.add(pendingConstructorCreation.create(objectFactory));
}
}
}
}
private void verifyPendingCreationPreconditions(ResultMapping parentMapping) {
if (parentMapping != null) {
throw new ExecutorException(
"Cannot construct objects with collections in constructors using multiple result sets yet!");
}
if (!mappedStatement.isResultOrdered()) {
throw new ExecutorException("Cannot reliably construct result if we are not sure the results are ordered "
+ "so that no new previous rows would occur, set resultOrdered on your mapped statement if you have verified this");
}
}
private void createAndStorePendingCreation(ResultHandler<?> resultHandler, ResultSet resultSet,
DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation) throws SQLException {
final Object result = pendingCreation.create(objectFactory);
storeObject(resultHandler, resultContext, result, null, resultSet);
nestedResultObjects.clear();
}
//
// NESTED RESULT MAP (JOIN MAPPING)
//
private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
String parentPrefix, CacheKey parentRowKey, boolean newObject) {
boolean foundValues = false;View on GitHub (pinned to 008069adb1)
Solutions
- Add resultOrdered="true" to the <select> statement AND make sure the query's ORDER BY groups all rows of each parent together (e.g. ORDER BY parent_id).
- If you cannot guarantee ordering, drop the constructor collection mapping and use a plain setter-based collection mapping.
- Split the query into separate statements (parent query + child query) and assemble in code.
Example fix
<!-- before --> <select id="selectParents" resultMap="parentMap"> SELECT p.id, p.name, c.id AS child_id FROM parent p LEFT JOIN child c ON c.parent_id = p.id ORDER BY p.id </select> <!-- after --> <select id="selectParents" resultMap="parentMap" resultOrdered="true"> SELECT p.id, p.name, c.id AS child_id FROM parent p LEFT JOIN child c ON c.parent_id = p.id ORDER BY p.id </select>
Defensive patterns
Strategy: validation
Validate before calling
// fail fast if a constructor-collection statement lacks resultOrdered
for (Object msObj : configuration.getMappedStatements()) {
if (msObj instanceof MappedStatement ms
&& ms.getResultMaps().stream().anyMatch(ResultMap::hasResultMapsUsingConstructorCollection)
&& !ms.isResultOrdered()) {
throw new IllegalStateException(ms.getId()
+ " uses constructor collections but resultOrdered=false; set resultOrdered='true' and ORDER BY parent key.");
}
} Prevention
- Always pair constructor-collection mappings with resultOrdered="true" AND an ORDER BY on the parent's key columns.
- Add a review checklist item: any JOIN mapped into constructor collections must be ordered and flagged.
When it happens
Trigger: A resultMap uses constructor collection mappings (nested pending constructor creations, e.g. resultMap.hasResultMapsUsingConstructorCollection()), the rows are not an outer-mapping (parentMapping == null), and the <select> lacks resultOrdered="true".
Common situations: Adopting constructor-based immutable mapping with collections for the first time; JOIN queries ordered by the parent key (which would satisfy the requirement) but with the flag forgotten; copy-pasted select statements that never needed the flag before.
Related errors
- Error in result map '{resultMapId}'. We do not support parti
- Error getting constructor collection nested result map value
- Cannot construct objects with collections in constructors us
- Cannot add a collection result to non-collection based resul
- Invalid bound statement (not found): {mapperInterface}.{meth
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/428789d9f14f5f11.
Report an issue: GitHub.