mybatis/mybatis-3 · error · ExecutorException

ResultLoader could not load lazily. Environment was not con

Error message

ResultLoader could not load lazily.  Environment was not configured.

What it means

ResultLoader.newExecutor builds a throwaway SIMPLE executor to run the nested query behind a lazy property, using the current Configuration's Environment (DataSource + TransactionFactory). If the Configuration has no Environment (typical when it was built programmatically or deserialized without one), lazy loading cannot open a connection and this ExecutorException is thrown.

Source

Thrown at src/main/java/org/apache/ibatis/executor/loader/ResultLoader.java:94

  private <E> List<E> selectList() throws SQLException {
    Executor localExecutor = executor;
    if (Thread.currentThread().getId() != this.creatorThreadId || localExecutor.isClosed()) {
      localExecutor = newExecutor();
    }
    try {
      return localExecutor.query(mappedStatement, parameterObject, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER,
          cacheKey, boundSql);
    } finally {
      if (localExecutor != executor) {
        localExecutor.close(false);
      }
    }
  }

  private Executor newExecutor() {
    final Environment environment = configuration.getEnvironment();
    if (environment == null) {
      throw new ExecutorException("ResultLoader could not load lazily.  Environment was not configured.");
    }
    final DataSource ds = environment.getDataSource();
    if (ds == null) {
      throw new ExecutorException("ResultLoader could not load lazily.  DataSource was not configured.");
    }
    final TransactionFactory transactionFactory = environment.getTransactionFactory();
    final Transaction tx = transactionFactory.newTransaction(ds, null, false);
    return configuration.newExecutor(tx, ExecutorType.SIMPLE);
  }

  public boolean wasNull() {
    return resultObject == null;
  }

}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Configure the Environment: configuration.setEnvironment(new Environment("id", transactionFactory, dataSource))
  2. Build the SqlSessionFactory with a SqlSessionFactoryBuilder and a parsed XML that contains <environments default=...>
  3. In Spring, let mybatis-spring create the factory so the Environment is always set

Example fix

// before
Configuration cfg = new Configuration();
new SqlSessionFactoryBuilder().build(cfg); // no Environment -> lazy load fails

// after
DataSource ds = ...;
Environment env = new Environment("dev", new JdbcTransactionFactory(), ds);
cfg.setEnvironment(env);
Defensive patterns

Strategy: validation

Validate before calling

// Verify at startup that lazy loading can work
if (configuration.getEnvironment() == null) {
  throw new IllegalStateException("An Environment (DataSource + TransactionFactory) is required for lazy loading");
}

Prevention

When it happens

Trigger: Accessing a lazy property when configuration.getEnvironment() returns null — programmatic Configuration without an Environment, a deserialized Configuration that lost it, or a custom SqlSessionFactory setup that skipped environment registration.

Common situations: Using new Configuration() directly and building a SqlSessionFactory without setting an Environment; unit tests with hand-built configurations; Spring setups that replace the environment incorrectly.

Related errors


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