mybatis/mybatis-3 · error · IllegalArgumentException

ResultMaps must have an id

Error message

ResultMaps must have an id

What it means

ResultMap.Builder.build() throws IllegalArgumentException when the resultMap being constructed has a null id. Every ResultMap must be identifiable (usually its namespace-qualified name) because statements, nested mappings and Discriminators reference result maps by id.

Source

Thrown at src/main/java/org/apache/ibatis/mapping/ResultMap.java:91

      resultMap.configuration = configuration;
      resultMap.id = id;
      resultMap.type = type;
      resultMap.resultMappings = resultMappings;
      resultMap.autoMapping = autoMapping;
    }

    public Builder discriminator(Discriminator discriminator) {
      resultMap.discriminator = discriminator;
      return this;
    }

    public Class<?> type() {
      return resultMap.type;
    }

    public ResultMap build() {
      if (resultMap.id == null) {
        throw new IllegalArgumentException("ResultMaps must have an id");
      }

      resultMap.mappedColumns = new HashSet<>();
      resultMap.mappedProperties = new HashSet<>();
      resultMap.idResultMappings = new ArrayList<>();
      resultMap.constructorResultMappings = new ArrayList<>();
      resultMap.propertyResultMappings = new ArrayList<>();

      for (ResultMapping resultMapping : resultMap.resultMappings) {
        resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null;
        resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || resultMapping.getNestedResultMapId() != null
            && resultMapping.getResultSet() == null && !JdbcType.CURSOR.equals(resultMapping.getJdbcType());
        final String column = resultMapping.getColumn();
        if (column != null) {
          resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
        } else if (resultMapping.isCompositeResult()) {
          for (ResultMapping compositeResultMapping : resultMapping.getComposites()) {
            final String compositeColumn = compositeResultMapping.getColumn();

View on GitHub (pinned to 008069adb1)

Solutions

  1. Pass a non-null, unique id: new ResultMap.Builder(config, "com.example.UserResult", User.class, mappings).build().
  2. When generating dynamically, derive the id from class + mapping hash to keep it stable and unique.
  3. Register the built ResultMap under the same id in Configuration.addResultMap so references resolve.

Example fix

// before
ResultMap rm = new ResultMap.Builder(config, null, User.class, mappings).build();

// after
ResultMap rm = new ResultMap.Builder(config, "com.example.mapper.UserMapper.UserResult", User.class, mappings).build();
Defensive patterns

Strategy: validation

Validate before calling

// Generate a stable unique id when building ResultMaps dynamically
String id = User.class.getName() + "#" + Integer.toHexString(mappings.hashCode());
ResultMap rm = new ResultMap.Builder(config, id, User.class, mappings).build();

Prevention

When it happens

Trigger: Programmatically building ResultMap without new ResultMap.Builder(configuration, null).with... — i.e. passing a null id; XML <resultMap> always generates an id, so this is almost exclusive to Java-built configurations and custom language drivers.

Common situations: Constructing ResultMaps dynamically (e.g. for dynamic schemas in generic frameworks) and forgetting to generate a unique id; utility code that copies ResultMaps but drops the id; third-party plugins built against older APIs.

Related errors


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