{"record":{"id":"58a6574b79183c68","repo":"mybatis/mybatis-3","slug":"parameter-transactionfactory-must-not-be-null","errorCode":null,"errorMessage":"Parameter 'transactionFactory' must not be null","messagePattern":"Parameter 'transactionFactory' must not be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/mapping/Environment.java","lineNumber":35,"sourceCode":"\nimport javax.sql.DataSource;\n\nimport org.apache.ibatis.transaction.TransactionFactory;\n\n/**\n * @author Clinton Begin\n */\npublic final class Environment {\n  private final String id;\n  private final TransactionFactory transactionFactory;\n  private final DataSource dataSource;\n\n  public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {\n    if (id == null) {\n      throw new IllegalArgumentException(\"Parameter 'id' must not be null\");\n    }\n    if (transactionFactory == null) {\n      throw new IllegalArgumentException(\"Parameter 'transactionFactory' must not be null\");\n    }\n    this.id = id;\n    if (dataSource == null) {\n      throw new IllegalArgumentException(\"Parameter 'dataSource' must not be null\");\n    }\n    this.transactionFactory = transactionFactory;\n    this.dataSource = dataSource;\n  }\n\n  public static class Builder {\n    private final String id;\n    private TransactionFactory transactionFactory;\n    private DataSource dataSource;\n\n    public Builder(String id) {\n      this.id = id;\n    }\n","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/mapping/Environment.java#L17-L53","documentation":"Environment's constructor throws IllegalArgumentException when transactionFactory is null. MyBatis needs a TransactionFactory (JdbcTransactionFactory or ManagedTransactionFactory) to open transactions for the environment, so it refuses null after the id check.","triggerScenarios":"new Environment(\"dev\", null, dataSource) — typically the factory variable was never initialized or the wrong branch of a conditional left it null.","commonSituations":"Switching from XML to Java-based config and forgetting new JdbcTransactionFactory(); DI containers not wiring the field; copy-paste of an Environment construction with the factory argument dropped.","solutions":["Pass a concrete factory: new JdbcTransactionFactory() (or ManagedTransactionFactory for container-managed transactions).","If built by DI, verify the TransactionFactory bean exists and is injected.","Add a null check earlier at the config-loading layer with a clearer message about which setting is missing."],"exampleFix":"// before\nEnvironment env = new Environment(\"dev\", null, dataSource);\n\n// after\nEnvironment env = new Environment(\"dev\", new JdbcTransactionFactory(), dataSource);","handlingStrategy":"validation","validationCode":"TransactionFactory txFactory = Objects.requireNonNull(txFactory, \"TransactionFactory not wired\");\nnew Environment(\"dev\", txFactory, ds);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose the factory deliberately: JdbcTransactionFactory for standalone apps, ManagedTransactionFactory in app servers.","With DI, mark the TransactionFactory bean as required so wiring fails at startup with a clear error.","Centralize Environment construction in one factory method instead of call sites."],"tags":["mybatis","configuration","transaction","null-check"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}