{"record":{"id":"428789d9f14f5f11","repo":"mybatis/mybatis-3","slug":"cannot-reliably-construct-result-if-we-are-not-sur","errorCode":null,"errorMessage":"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","messagePattern":"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","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java","lineNumber":1385,"sourceCode":"\n      // create the pending objects\n      for (Object pendingCreation : pendingCreations) {\n        if (pendingCreation instanceof PendingConstructorCreation) {\n          final PendingConstructorCreation pendingConstructorCreation = (PendingConstructorCreation) pendingCreation;\n          targetMetaObject.add(pendingConstructorCreation.create(objectFactory));\n        }\n      }\n    }\n  }\n\n  private void verifyPendingCreationPreconditions(ResultMapping parentMapping) {\n    if (parentMapping != null) {\n      throw new ExecutorException(\n          \"Cannot construct objects with collections in constructors using multiple result sets yet!\");\n    }\n\n    if (!mappedStatement.isResultOrdered()) {\n      throw new ExecutorException(\"Cannot reliably construct result if we are not sure the results are ordered \"\n          + \"so that no new previous rows would occur, set resultOrdered on your mapped statement if you have verified this\");\n    }\n  }\n\n  private void createAndStorePendingCreation(ResultHandler<?> resultHandler, ResultSet resultSet,\n      DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation) throws SQLException {\n    final Object result = pendingCreation.create(objectFactory);\n    storeObject(resultHandler, resultContext, result, null, resultSet);\n    nestedResultObjects.clear();\n  }\n\n  //\n  // NESTED RESULT MAP (JOIN MAPPING)\n  //\n\n  private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,\n      String parentPrefix, CacheKey parentRowKey, boolean newObject) {\n    boolean foundValues = false;","sourceCodeStart":1367,"sourceCodeEnd":1403,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java#L1367-L1403","documentation":"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.","triggerScenarios":"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\".","commonSituations":"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.","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."],"exampleFix":"<!-- before -->\n<select id=\"selectParents\" resultMap=\"parentMap\">\n  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\n</select>\n\n<!-- after -->\n<select id=\"selectParents\" resultMap=\"parentMap\" resultOrdered=\"true\">\n  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\n</select>","handlingStrategy":"validation","validationCode":"// fail fast if a constructor-collection statement lacks resultOrdered\nfor (Object msObj : configuration.getMappedStatements()) {\n  if (msObj instanceof MappedStatement ms\n      && ms.getResultMaps().stream().anyMatch(ResultMap::hasResultMapsUsingConstructorCollection)\n      && !ms.isResultOrdered()) {\n    throw new IllegalStateException(ms.getId()\n        + \" uses constructor collections but resultOrdered=false; set resultOrdered='true' and ORDER BY parent key.\");\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["mybatis","resultordered","constructor-mapping","collections","configuration"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}