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

  1. 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).
  2. If you cannot guarantee ordering, drop the constructor collection mapping and use a plain setter-based collection mapping.
  3. 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

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


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