mybatis/mybatis-3 · error · ExecutorException

Constructor auto-mapping of ''{1}'' failed because ''{0}'' w

Error message

Constructor auto-mapping of ''{1}'' failed because ''{0}'' were not found in the result set; Available columns are ''{2}'' and mapUnderscoreToCamelCase is ''{3}''.

What it means

Thrown during argument-name-based constructor auto-mapping when at least one column matched and produced a value, but some constructor parameters had no matching column in the result set. The message lists the missing parameter names, the available column names, and the current mapUnderscoreToCamelCase setting, since a name/case/underscore mismatch is the usual cause.

Source

Thrown at src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java:964

          constructorArgTypes.add(paramType);
          constructorArgs.add(value);
          final String mapKey = resultMap.getId() + ":" + columnPrefix;
          if (!autoMappingsCache.containsKey(mapKey)) {
            constructorAutoMappingColumns.computeIfAbsent(mapKey, k -> new ArrayList<>()).add(columnName);
          }
          columnNotFound = false;
          foundValues = value != null || foundValues;
        }
      }
      if (columnNotFound) {
        if (missingArgs == null) {
          missingArgs = new ArrayList<>();
        }
        missingArgs.add(paramName);
      }
    }
    if (foundValues && constructorArgs.size() < params.length) {
      throw new ExecutorException(MessageFormat.format(
          "Constructor auto-mapping of ''{1}'' failed " + "because ''{0}'' were not found in the result set; "
              + "Available columns are ''{2}'' and mapUnderscoreToCamelCase is ''{3}''.",
          missingArgs, constructor, rsw.getColumnNames(), configuration.isMapUnderscoreToCamelCase()));
    }
    return foundValues;
  }

  private boolean columnMatchesParam(String columnName, String paramName, String columnPrefix) {
    if (columnPrefix != null) {
      if (!columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
        return false;
      }
      columnName = columnName.substring(columnPrefix.length());
    }
    return paramName
        .equalsIgnoreCase(configuration.isMapUnderscoreToCamelCase() ? columnName.replace("_", "") : columnName);
  }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Alias the SQL columns to match constructor parameter names exactly: SELECT user_name AS userName.
  2. Enable mapUnderscoreToCamelCase (<setting name="mapUnderscoreToCamelCase" value="true"/>) if columns are snake_case and parameters camelCase.
  3. Add the missing column(s) to the SELECT list, or remove/rename the constructor parameter to an existing column.
  4. Verify the code was compiled with -parameters so parameter names are the real names, not arg0/arg1.

Example fix

// before
// mybatis-config.xml: mapUnderscoreToCamelCase=false
// SELECT id, user_name FROM users
public User(Long id, String userName) { ... } // 'userName' not found

// after
// mybatis-config.xml: <setting name="mapUnderscoreToCamelCase" value="true"/>
// SELECT id, user_name FROM users
public User(Long id, String userName) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// after compiling with -parameters, assert every ctor param has a matching column
List<String> cols = ...; // from ResultSetMetaData.getColumnLabels, upper-cased
boolean camel = configuration.isMapUnderscoreToCamelCase();
for (Parameter p : ctor.getParameters()) {
  String expected = camel
      ? Arrays.stream(p.getName().split("(?=[A-Z])")).map(String::toLowerCase).collect(joining("_"))
      : p.getName();
  if (!cols.contains(expected.toUpperCase(Locale.ENGLISH))) {
    throw new IllegalStateException("No column for constructor param '" + p.getName() + "'; columns: " + cols);
  }
}

Prevention

When it happens

Trigger: argNameBasedConstructorAutoMapping enabled, class compiled with -parameters (or explicit param names), query executed, and a constructor parameter name (after optional underscore-to-camel translation and column prefix stripping via columnMatchesParam) matches no column in rsw.getColumnNames(). Only thrown when foundValues is true, i.e. partial matching succeeded.

Common situations: DB columns use snake_case (user_name) but mapUnderscoreToCamelCase is false and the parameter is userName; column aliases renamed in SQL; SELECT omits one column the constructor declares; parameter renamed in a refactor while the SQL stayed; joined/prefixed result maps where the prefix does not match.

Related errors


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