{"record":{"id":"083b303020d94fb4","repo":"mybatis/mybatis-3","slug":"error-in-result-map-resultmapid-failed-to-fin","errorCode":null,"errorMessage":"Error in result map '{resultMapId}'. Failed to find a constructor in '{resultType}' with arg names {constructorArgsByName}. Note that 'javaType' is required when there is ambiguous constructors or there is no writable property with the same name ('name' is optional, BTW). There is more info in the debug log.","messagePattern":"Error in result map '(.+?)'\\. Failed to find a constructor in '(.+?)' with arg names (.+?)\\. Note that 'javaType' is required when there is ambiguous constructors or there is no writable property with the same name \\('name' is optional, BTW\\)\\. There is more info in the debug log\\.","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/builder/ResultMappingConstructorResolver.java","lineNumber":125,"sourceCode":"        .filter(Objects::nonNull).collect(Collectors.toCollection(LinkedHashSet::new));\n\n    // arg order can only be 'fixed' if all mappings have property names\n    final boolean allMappingsHavePropertyNames = verifyPropertyNaming(constructorArgsByName);\n\n    // only do this if all property mappings were set\n    if (allMappingsHavePropertyNames) {\n      // while we have candidates, start selection\n      removeCandidatesBasedOnParameterNames(matchingConstructorCandidates, constructorArgsByName);\n    }\n\n    // resolve final constructor by filtering out selection based on type info present (or missing)\n    final ConstructorMetaInfo matchingConstructorInfo = filterBasedOnType(matchingConstructorCandidates,\n        constructorResultMappings, allMappingsHavePropertyNames);\n    if (matchingConstructorInfo == null) {\n      // [backwards-compatibility] (we cannot find a constructor),\n      // but this used to get thrown ONLY when property mappings have been set\n      if (allMappingsHavePropertyNames) {\n        throw new BuilderException(\"Error in result map '\" + resultMapId + \"'. Failed to find a constructor in '\"\n            + resultType.getName() + \"' with arg names \" + constructorArgsByName\n            + \". Note that 'javaType' is required when there is ambiguous constructors or there is no writable property with the same name ('name' is optional, BTW). There is more info in the debug log.\");\n      } else {\n        if (log.isDebugEnabled()) {\n          log.debug(\"Constructor for '\" + resultMapId + \"' could not be resolved.\");\n        }\n        // return un-modified original mappings\n        return constructorResultMappings;\n      }\n    }\n\n    // only rebuild (auto-type) if required (any types are unidentified)\n    final boolean autoTypeRequired = constructorResultMappings.stream().map(ResultMapping::getJavaType)\n        .anyMatch(mappingType -> mappingType == null || Object.class.equals(mappingType));\n    final List<ResultMapping> resultMappings = autoTypeRequired\n        ? autoTypeConstructorMappings(matchingConstructorInfo, constructorResultMappings, allMappingsHavePropertyNames)\n        : constructorResultMappings;\n","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/builder/ResultMappingConstructorResolver.java#L107-L143","documentation":"Thrown by ResultMappingConstructorResolver when automapping by constructor: all <constructor>/<arg> mappings have name attributes (constructorArgsByName fully populated) and no constructor of resultType could be matched after filtering candidates by parameter names and by supplied type info (javaType). The message notes that javaType is required when constructors are ambiguous or when arg names do not match writable properties.","triggerScenarios":"A <constructor> block whose arg name attributes don't match any actual constructor parameter names (e.g. names compiled without -parameters, or name mismatch), multiple constructors of the same arity with no javaType hints to disambiguate, or resultType lacking a matching-arity constructor.","commonSituations":"DTOs/records with multiple constructors; compiled code without the -parameters flag so reflection cannot read parameter names; renaming DTO fields without updating mapper constructor args; constructor arg count mismatch after adding a field.","solutions":["Add explicit javaType (and jdbcType where needed) to each <arg>/<@Arg> so type-based filtering can pick the right constructor","Make sure every arg name matches the constructor parameter name exactly (enable -parameters compiler flag for automatic param names)","Verify a public constructor exists whose parameter count equals the number of constructor args","Check the debug log (enable DEBUG for that logger) — it lists candidate constructors that were rejected and why"],"exampleFix":"<!-- before -->\n<constructor>\n  <arg column=\"user_name\" name=\"userName\"/>\n</constructor>\n<!-- after -->\n<constructor>\n  <arg column=\"user_name\" name=\"userName\" javaType=\"java.lang.String\"/>\n</constructor>","handlingStrategy":"validation","validationCode":"// Verify a matching constructor exists before relying on constructor automapping\nstatic void assertConstructorMatch(Class<?> dto, List<String> argNames, List<Class<?>> argTypes) {\n  boolean ok = Arrays.stream(dto.getDeclaredConstructors()).anyMatch(c -> {\n    if (c.getParameterCount() != argNames.size()) return false;\n    Parameter[] params = c.getParameters();\n    for (int i = 0; i < params.length; i++) {\n      if (!params[i].getName().equals(argNames.get(i))) return false;\n      if (argTypes.get(i) != null && !params[i].getType().equals(argTypes.get(i))) return false;\n    }\n    return true;\n  });\n  if (!ok) throw new IllegalStateException(\"No constructor of \" + dto.getName() + \" matches args \" + argNames);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compile with -parameters (javac) so constructor parameter names are visible to MyBatis","Add explicit javaType to <arg>/@Arg when the DTO has multiple constructors","Write a config-load test that executes one query per resultMap so constructor issues fail in CI"],"tags":["mybatis","resultmap","constructor-mapping","reflection"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}