mybatis/mybatis-3 · error · ExecutorException
Too many keys are generated. There are only %d target object
Error message
Too many keys are generated. There are only %d target object(s). A 'Map' passed as the sole parameter is treated as a single target object, so keys generated by a multi-row insert cannot be assigned to a collection nested in the 'Map'. Pass the collection itself as the sole parameter, or declare the parameters with @Param and prefix 'keyProperty' with the parameter name (e.g. 'list.id').
What it means
During a multi-row insert (single insert statement with a collection parameter), Jdbc3KeyGenerator iterates the generated-keys ResultSet side by side with the parameter objects. When a java.util.Map is the sole parameter, MyBatis treats the whole Map as ONE target object, so if the insert generated several keys (one per row) there are more keys than targets and this ExecutorException is thrown, explaining that a Map cannot receive per-row keys.
Source
Thrown at src/main/java/org/apache/ibatis/executor/keygen/Jdbc3KeyGenerator.java:126
// Single param without @Param
assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
}
}
private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, Object parameter) throws SQLException {
Collection<?> params = collectionize(parameter);
if (params.isEmpty()) {
return;
}
List<KeyAssigner> assignerList = new ArrayList<>();
for (int i = 0; i < keyProperties.length; i++) {
assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i]));
}
Iterator<?> iterator = params.iterator();
while (rs.next()) {
if (!iterator.hasNext()) {
throw new ExecutorException(
String.format(parameter instanceof Map ? MSG_TOO_MANY_KEYS_FOR_MAP : MSG_TOO_MANY_KEYS, params.size()));
}
Object param = iterator.next();
assignerList.forEach(x -> x.assign(rs, param));
}
}
private void assignKeysToParamMapList(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, ArrayList<ParamMap<?>> paramMapList) throws SQLException {
Iterator<ParamMap<?>> iterator = paramMapList.iterator();
List<KeyAssigner> assignerList = new ArrayList<>();
long counter = 0;
while (rs.next()) {
if (!iterator.hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
}
ParamMap<?> paramMap = iterator.next();
if (assignerList.isEmpty()) {View on GitHub (pinned to 008069adb1)
Solutions
- Pass the collection itself as the sole parameter: List<User> insert(List<User> users)
- Or declare parameters with @Param and prefix keyProperty with the parameter name: keyProperty="list.id"
- Do not use a bare Map as the sole parameter of a multi-row insert that needs generated keys assigned
Example fix
// before
Map<String,Object> m = Map.of("list", users);
mapper.insert(m); // with keyProperty="id" -> exception
// after
int insert(@Param("list") List<User> users); // keyProperty="list.id" Defensive patterns
Strategy: validation
Validate before calling
// Guard before a multi-row insert with generated keys
if (params instanceof Map && !(params instanceof List)) {
throw new IllegalArgumentException("Pass the collection itself or use @Param + 'keyProperty=list.id'");
} Prevention
- Never use a bare Map as the sole parameter for multi-row inserts needing generated keys
- Standardize on @Param("list") + keyProperty="list.id" for batch inserts
When it happens
Trigger: A multi-row INSERT ... VALUES (row1),(row2) with useGeneratedKeys where the single parameter is a Map (e.g. @Param map or a plain HashMap) that merely CONTAINS the collection (e.g. map.put("list", items)) instead of the collection being the parameter itself.
Common situations: Wrapping a list in a Map to pass extra data (map.put("items", list)) and still expecting each generated key to land inside map.items[i].id.
Related errors
- Too many keys are generated. There are only %d target object
- Error getting generated key or setting result to parameter o
- Could not determine which parameter to assign generated keys
- Could not find parameter '${paramName}'. Note that when ther
- No setter found for the keyProperty '${propertyName}' in '${
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/cc00a0aed490b135.
Report an issue: GitHub.