mybatis/mybatis-3 · error · IllegalArgumentException

Cannot convert {} to {} by ordinal value.

Error message

Cannot convert {} to {} by ordinal value.

What it means

EnumOrdinalTypeHandler maps database integers to enum constants by array position (ordinal). When the integer read from the column is negative or >= enums.length, the array access fails and toOrdinalEnum throws this IllegalArgumentException showing the raw value and the target enum name.

Source

Thrown at src/main/java/org/apache/ibatis/type/EnumOrdinalTypeHandler.java:78

      return null;
    }
    return toOrdinalEnum(ordinal);
  }

  @Override
  public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    int ordinal = cs.getInt(columnIndex);
    if (ordinal == 0 && cs.wasNull()) {
      return null;
    }
    return toOrdinalEnum(ordinal);
  }

  private E toOrdinalEnum(int ordinal) {
    try {
      return enums[ordinal];
    } catch (Exception ex) {
      throw new IllegalArgumentException(
          "Cannot convert " + ordinal + " to " + type.getSimpleName() + " by ordinal value.", ex);
    }
  }
}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Reconcile the data: update the column to valid ordinals, or restore/reorder the enum constants to match the data
  2. Switch to EnumTypeHandler (name-based mapping) so stored values survive reordering — migrate the column to the enum names
  3. Add a data constraint/validation on write so only valid ordinals can be persisted

Example fix

// before
public enum Status { ACTIVE, CLOSED } // DB has 5; row was written when enum had 6 values

// after
// migrate column to names and map by name
<result column="status" property="status" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
Defensive patterns

Strategy: try-catch

Validate before calling

// guard on read inside a custom handler
int ordinal = rs.getInt(column);
if (ordinal < 0 || ordinal >= Status.values().length) {
  log.warn("Unknown ordinal {} for Status", ordinal);
  return null;
}

Type guard

static Status fromOrdinal(int o) {
  Status[] v = Status.values();
  return (o >= 0 && o < v.length) ? v[o] : null;
}

Try / catch

try { ... } catch (IllegalArgumentException e) { if (e.getMessage().contains("by ordinal value")) { /* map unknown ordinals to a default/null instead of failing the query */ } }

Prevention

When it happens

Trigger: The column contains an ordinal that no longer exists in the enum: enum constants were reordered or deleted after the rows were written; the column stores a different numbering scheme (e.g. 1-based) than Java ordinals (0-based); hand-edited/seeded data.

Common situations: Inserting/reordering enum constants between releases; importing data where the status column is 1-based; a different application writing ordinals from its own enum ordering.

Related errors


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