{"record":{"id":"da554b244501b351","repo":"mybatis/mybatis-3","slug":"no-setter-found-for-the-keyproperty-property","errorCode":null,"errorMessage":"No setter found for the keyProperty '\" + property + \"' in \" + metaParam.getOriginalObject().getClass().getName() + \".\"","messagePattern":"No setter found for the keyProperty '\" \\+ property \\+ \"' in \" \\+ metaParam\\.getOriginalObject\\(\\)\\.getClass\\(\\)\\.getName\\(\\) \\+ \"\\.\"","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java","lineNumber":116,"sourceCode":"    if (keyColumns == null || keyColumns.length == 0) {\n      // no key columns specified, just use the property names\n      for (String keyProperty : keyProperties) {\n        setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));\n      }\n    } else {\n      if (keyColumns.length != keyProperties.length) {\n        throw new ExecutorException(\n            \"If SelectKey has key columns, the number must match the number of key properties.\");\n      }\n      for (int i = 0; i < keyProperties.length; i++) {\n        setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));\n      }\n    }\n  }\n\n  private void setValue(MetaObject metaParam, String property, Object value) {\n    if (!metaParam.hasSetter(property)) {\n      throw new ExecutorException(\"No setter found for the keyProperty '\" + property + \"' in \"\n          + metaParam.getOriginalObject().getClass().getName() + \".\");\n    }\n    metaParam.setValue(property, value);\n  }\n}\n","sourceCodeStart":98,"sourceCodeEnd":122,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java#L98-L122","documentation":"Before writing the key value into the parameter object, setValue checks metaParam.hasSetter(property). If the insert's parameter object has no setter for the declared keyProperty, this ExecutorException naming the property and class is thrown. Unlike Jdbc3KeyGenerator's check, this one runs against the top-level parameter object for every keyProperty/keyColumn pair.","triggerScenarios":"<selectKey keyProperty=\"userId\"> when the parameter class lacks setUserId; immutable parameter classes; misspelled or wrong-case property; keyProperty containing a prefix that does not resolve on this parameter object.","commonSituations":"Using Lombok @Value or builder-only classes as insert parameters, records, or renamed DTO fields without updating the mapper XML.","solutions":["Add a setter for the keyProperty on the parameter class","Correct the property name in keyProperty to match the class's setter","Use a mutable POJO as the insert parameter instead of an immutable one"],"exampleFix":"// before\nclass Order { private Long orderId; /* getters only */ }\n\n// after\nclass Order { private Long orderId; public Long getOrderId() {...} public void setOrderId(Long id) { this.orderId = id; } }","handlingStrategy":"validation","validationCode":"// Assert the parameter object can receive the key before mapping\nMetaObject mo = configuration.newMetaObject(new Order());\nfor (String kp : new String[]{\"orderId\"}) {\n  if (!mo.hasSetter(kp)) throw new IllegalStateException(\"missing setter: \" + kp);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure insert parameter classes have setters for every keyProperty","Rename keyProperty when renaming DTO fields"],"tags":["selectkey","setter","reflection"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}