{"record":{"id":"3cbe59de6a92cd6e","repo":"mybatis/mybatis-3","slug":"nested-lazy-loaded-result-property-property","errorCode":null,"errorMessage":"Nested lazy loaded result property '\" + property + \"' for query id '\" + resultLoader.mappedStatement.getId() + \" already exists in the result map. The leftmost property of all lazy loaded properties must be unique within a result map.\"","messagePattern":"Nested lazy loaded result property '\" \\+ property \\+ \"' for query id '\" \\+ resultLoader\\.mappedStatement\\.getId\\(\\) \\+ \" already exists in the result map\\. The leftmost property of all lazy loaded properties must be unique within a result map\\.\"","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/loader/ResultLoaderMap.java","lineNumber":55,"sourceCode":"import org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.apache.ibatis.session.Configuration;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * @author Clinton Begin\n * @author Franta Mejta\n */\npublic class ResultLoaderMap {\n\n  private final Map<String, LoadPair> loaderMap = new HashMap<>();\n\n  public void addLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader) {\n    String upperFirst = getUppercaseFirstProperty(property);\n    if (!upperFirst.equalsIgnoreCase(property) && loaderMap.containsKey(upperFirst)) {\n      throw new ExecutorException(\"Nested lazy loaded result property '\" + property + \"' for query id '\"\n          + resultLoader.mappedStatement.getId()\n          + \" already exists in the result map. The leftmost property of all lazy loaded properties must be unique within a result map.\");\n    }\n    loaderMap.put(upperFirst, new LoadPair(property, metaResultObject, resultLoader));\n  }\n\n  public final Map<String, LoadPair> getProperties() {\n    return new HashMap<>(this.loaderMap);\n  }\n\n  public Set<String> getPropertyNames() {\n    return loaderMap.keySet();\n  }\n\n  public int size() {\n    return loaderMap.size();\n  }\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/loader/ResultLoaderMap.java#L37-L73","documentation":"ResultLoaderMap keys pending lazy loads by the LEFTMOST segment of the property path (order.customer -> 'order'). Two lazy properties in one resultMap that share the same leftmost segment would fight over the same loader slot and overwrite each other, so addLoader rejects the second one with this ExecutorException. Note the message contains a known typo ('query id ... already exists' string concatenation).","triggerScenarios":"A resultMap declaring two nested selects whose property paths start with the same segment, e.g. property=\"orders.pending\" and property=\"orders.shipped\" — both map to key 'orders'.","commonSituations":"Splitting one association into multiple lazy sub-properties under the same parent name; refactoring resultMaps during entity redesign.","solutions":["Give the two lazy properties distinct leftmost segments, e.g. property=\"pendingOrders\" and property=\"shippedOrders\"","Combine them into a single nested select that populates the shared parent in one query"],"exampleFix":"<!-- before -->\n<resultMap id=\"m\" type=\"T\">\n  <association property=\"orders.pending\" select=\"selPending\" fetchType=\"lazy\"/>\n  <association property=\"orders.shipped\" select=\"selShipped\" fetchType=\"lazy\"/>\n</resultMap>\n\n<!-- after -->\n<resultMap id=\"m\" type=\"T\">\n  <association property=\"pendingOrders\" select=\"selPending\" fetchType=\"lazy\"/>\n  <association property=\"shippedOrders\" select=\"selShipped\" fetchType=\"lazy\"/>\n</resultMap>","handlingStrategy":"validation","validationCode":"// Lint resultMaps: no two lazy properties may share a leftmost segment\nSet<String> leftmost = new HashSet<>();\nfor (String prop : lazyPropertyPaths) {\n  String head = prop.split(\"\\\\.\")[0];\n  if (!leftmost.add(head)) throw new IllegalStateException(\"duplicate leftmost lazy property: \" + head);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep one nested select per top-level lazy property in each resultMap","Review resultMaps after splitting associations into sub-properties"],"tags":["lazy-loading","resultmap","nested-select"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}