mybatis/mybatis-3 · error · ExecutorException

Could not determine which parameter to assign generated keys

Error message

Could not determine which parameter to assign generated keys to. Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). Specified key properties are ${keyProperties} and available parameters are ${keySet}

What it means

getAssignerForParamMap decides which parameter object receives each generated key. When a mapper method has multiple parameters (the ParamMap contains more than one name), MyBatis cannot guess which parameter a bare keyProperty like 'id' belongs to, so it requires the parameter name to be embedded in the keyProperty (e.g. 'item.id'). Without the prefix, this ExecutorException listing the specified keyProperties and available parameter names is thrown.

Source

Thrown at src/main/java/org/apache/ibatis/executor/keygen/Jdbc3KeyGenerator.java:193

        Object param = pair.getKey().next();
        pair.getValue().forEach(x -> x.assign(rs, param));
      }
      counter++;
    }
  }

  private Entry<String, KeyAssigner> getAssignerForParamMap(Configuration config, ResultSetMetaData rsmd,
      int columnPosition, Map<String, ?> paramMap, String keyProperty, String[] keyProperties, boolean omitParamName) {
    Set<String> keySet = paramMap.keySet();
    // A caveat : if the only parameter has {@code @Param("param2")} on it,
    // it must be referenced with param name e.g. 'param2.x'.
    boolean singleParam = !keySet.contains(SECOND_GENERIC_PARAM_NAME);
    int firstDot = keyProperty.indexOf('.');
    if (firstDot == -1) {
      if (singleParam) {
        return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
      }
      throw new ExecutorException("Could not determine which parameter to assign generated keys to. "
          + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
          + "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
          + keySet);
    }
    String paramName = keyProperty.substring(0, firstDot);
    if (keySet.contains(paramName)) {
      String argParamName = omitParamName ? null : paramName;
      String argKeyProperty = keyProperty.substring(firstDot + 1);
      return Map.entry(paramName, new KeyAssigner(config, rsmd, columnPosition, argParamName, argKeyProperty));
    }
    if (singleParam) {
      return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
    } else {
      throw new ExecutorException("Could not find parameter '" + paramName + "'. "
          + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
          + "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
          + keySet);
    }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Prefix keyProperty with the parameter name: keyProperty="user.id" (or the @Param name)
  2. Keep the insert method single-parameter so a bare keyProperty is unambiguous
  3. Verify the parameter name matches the @Param annotation or the mapped key shown in the error's 'available parameters' list

Example fix

<!-- before -->
int insert(@Param("user") User user, @Param("flag") int flag);
<insert ... keyProperty="id">

<!-- after -->
<insert ... keyProperty="user.id">
Defensive patterns

Strategy: validation

Validate before calling

// Convention check in a shared base mapper or code review rule:
// any insert method with >1 parameter must use keyProperty="<paramName>.<prop>"
int paramCount = method.getParameters().length;
if (paramCount > 1 && !keyProperty.contains(".")) throw new IllegalStateException("keyProperty must be prefixed with the parameter name");

Prevention

When it happens

Trigger: Mapper method with two or more parameters (with or without @Param) combined with useGeneratedKeys="true" and a keyProperty that has no dot, e.g. keyProperty="id" instead of keyProperty="user.id".

Common situations: Adding an extra parameter (e.g. a flag or a second entity) to an existing single-param insert method and forgetting to prefix keyProperty; using Map<String,Object> with multiple entries as sole parameter.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/2f2c270e3806116c. Report an issue: GitHub.