{"record":{"id":"90e59a0e70ec9ea0","repo":"mybatis/mybatis-3","slug":"expected-result-object-to-be-a-pending-constructor","errorCode":null,"errorMessage":"Expected result object to be a pending constructor creation!","messagePattern":"Expected result object to be a pending constructor creation!","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java","lineNumber":410,"sourceCode":"              + \"or ensure your statement returns ordered data and set resultOrdered=true on it.\");\n    }\n  }\n\n  private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,\n      ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {\n    final boolean useCollectionConstructorInjection = resultMap.hasResultMapsUsingConstructorCollection();\n\n    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();\n    ResultSet resultSet = rsw.getResultSet();\n    skipRows(resultSet, rowBounds);\n    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {\n      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw, resultMap, null);\n      Object rowValue = getRowValue(rsw, discriminatedResultMap, null, null);\n      if (!useCollectionConstructorInjection) {\n        storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);\n      } else {\n        if (!(rowValue instanceof PendingConstructorCreation)) {\n          throw new ExecutorException(\"Expected result object to be a pending constructor creation!\");\n        }\n\n        createAndStorePendingCreation(resultHandler, resultSet, resultContext, (PendingConstructorCreation) rowValue);\n      }\n    }\n  }\n\n  private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue,\n      ResultMapping parentMapping, ResultSet rs) throws SQLException {\n    if (parentMapping != null) {\n      linkToParents(rs, parentMapping, rowValue);\n      return;\n    }\n\n    if (pendingPccRelations.containsKey(rowValue)) {\n      createPendingConstructorCreations(rowValue);\n    }\n","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java#L392-L428","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"<!-- before: mixed styles -> inconsistent internal state -->\n<resultMap id=\"orderMap\" type=\"Order\">\n  <constructor><arg column=\"id\" javaType=\"long\"/></constructor>\n  <collection property=\"items\" ofType=\"Item\"/>  <!-- property collection alongside ctor flags -->\n</resultMap>\n<!-- after: single style -->\n<resultMap id=\"orderMap\" type=\"Order\">\n  <id property=\"id\" column=\"id\"/>\n  <collection property=\"items\" ofType=\"Item\"/>\n</resultMap>","handlingStrategy":"validation","validationCode":"// Keep mappings single-style: either constructor-collection or property collections\nResultMap rm = session.getConfiguration().getResultMap(\"orderMap\");\nif (rm.hasResultMapsUsingConstructorCollection() && rm.getResultMappings().stream().anyMatch(m -> m.getNestedResultMapId() != null && m.getProperty() != null)) {\n  log.warn(\"Mixed constructor-collection and property collection mapping in {}\", rm.getId());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["mybatis","constructor-mapping","nested-results","internal-invariant"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}