mybatis/mybatis-3 · error · ExecutorException

Unknown statement type: {}

Error message

Unknown statement type: {}

What it means

RoutingStatementHandler switches on mappedStatement.getStatementType() and knows only STATEMENT, PREPARED, and CALLABLE. Any other value falls through to 'Unknown statement type'. With the stock StatementType enum this is defensive dead code; in practice it appears when a custom/modified enum, a different MyBatis fork, or a corrupted serialization of MappedStatement introduces an unexpected value.

Source

Thrown at src/main/java/org/apache/ibatis/executor/statement/RoutingStatementHandler.java:53

public class RoutingStatementHandler implements StatementHandler {

  private final StatementHandler delegate;

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
      ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    return delegate.prepare(connection, transactionTimeout);
  }

  @Override
  public void parameterize(Statement statement) throws SQLException {
    delegate.parameterize(statement);
  }

  @Override
  public void batch(Statement statement) throws SQLException {
    delegate.batch(statement);
  }

View on GitHub (pinned to 008069adb1)

Solutions

  1. Align all MyBatis artifacts to one version (check mvn dependency:tree for mybatis* artifacts).
  2. Remove duplicate/forked mybatis jars from the classpath so a single StatementType enum is used.
  3. If you maintain a fork adding a statement type, extend RoutingStatementHandler's switch accordingly.
  4. Do not cache or transport MappedStatement objects across different MyBatis versions.
Defensive patterns

Strategy: validation

Validate before calling

// startup check: exactly one mybatis core on the classpath
Enumeration<URL> jars = getClass().getClassLoader().getResources("org/apache/ibatis/session/Configuration.class");
List<URL> found = Collections.list(jars);
if (found.size() != 1) {
  throw new IllegalStateException("Multiple/split mybatis classes found: " + found);
}

Prevention

When it happens

Trigger: Constructing a RoutingStatementHandler for a MappedStatement whose statementType is not one of the three known enum constants — e.g. custom StatementType extension, MappedStatement deserialized from an incompatible version, or shaded/duplicated mybatis jars with diverging enums.

Common situations: Mixing MyBatis versions on the classpath (mybatis + mybatis-spring or mybatis-plus pulling different versions); caching/serializing MappedStatement across versions; custom source forks adding a new statement type without updating RoutingStatementHandler.

Related errors


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