mybatis/mybatis-3 · error · IllegalStateException

There should be the same number of columns and…

Error message

There should be the same number of columns and foreignColumns in property {}

What it means

Thrown by ResultMapping.Builder.validate() for joined/multiple result sets (resultSet attribute present). When a mapping declares a resultSet, MyBatis pairs each column with a foreignColumn to correlate rows across result sets, so both lists must have the same length after splitting on commas.

Solutions

  1. Count entries in column and foreignColumn and make them match (column="a,b" foreignColumn="x,y").
  2. Remove stray spaces or empty segments caused by trailing/double commas in either attribute.
  3. If the correlation key is single-column, keep exactly one column and one foreignColumn.

Example fix

<!-- before -->
<association property="author" javaType="Author" resultSet="authorsRS" column="id,tenant" foreignColumn="authorId"/>
<!-- after -->
<association property="author" javaType="Author" resultSet="authorsRS" column="id,tenant" foreignColumn="authorId,authorTenant"/>
Defensive patterns

Strategy: validation

Validate before calling

int cols = column == null ? 0 : column.split(",").length;
int foreign = foreignColumn == null ? 0 : foreignColumn.split(",").length;
if (resultSet != null && cols != foreign) throw new IllegalArgumentException("column/foreignColumn count mismatch");

Prevention

When it happens

Trigger: An <association> or <collection> with resultSet="..." where the comma-separated lists in column and foreignColumn differ in length, e.g. column="a,b" with foreignColumn="c".

Common situations: Stored procedures returning multiple result sets joined by composite keys; developer adds one side of a two-part key but not the other; stray/missing commas in the lists.

Related errors


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

Appendix: source

Thrown at src/main/java/org/apache/ibatis/mapping/ResultMapping.java:181

        throw new IllegalStateException(
            "Cannot define both nestedQueryId and nestedResultMapId in property " + resultMapping.property);
      }
      // Issue #4 and GH #39: column is optional only in nested resultMaps but not in the rest
      if (resultMapping.nestedResultMapId == null && resultMapping.column == null
          && resultMapping.composites.isEmpty()) {
        throw new IllegalStateException("Mapping is missing column attribute for property " + resultMapping.property);
      }
      if (resultMapping.getResultSet() != null) {
        int numColumns = 0;
        if (resultMapping.column != null) {
          numColumns = resultMapping.column.split(",").length;
        }
        int numForeignColumns = 0;
        if (resultMapping.foreignColumn != null) {
          numForeignColumns = resultMapping.foreignColumn.split(",").length;
        }
        if (numColumns != numForeignColumns) {
          throw new IllegalStateException(
              "There should be the same number of columns and foreignColumns in property " + resultMapping.property);
        }
      }
    }

    public Builder column(String column) {
      resultMapping.column = column;
      return this;
    }
  }

  public String getProperty() {
    return property;
  }

  public String getColumn() {
    return column;
  }

View on GitHub (pinned to 008069adb1)