{"record":{"id":"ff68aa6aebcee81c","repo":"mybatis/mybatis-3","slug":"cannot-get-configuration-as-configuration-factory","errorCode":null,"errorMessage":"Cannot get Configuration as configuration factory was not set.","messagePattern":"Cannot get Configuration as configuration factory was not set\\.","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/loader/ResultLoaderMap.java","lineNumber":227,"sourceCode":"            metaResultObject.getSetterType(this.property), null, null);\n      }\n\n      /*\n       * We are using a new executor because we may be (and likely are) on a new thread and executors aren't thread\n       * safe. (Is this sufficient?) A better approach would be making executors thread safe.\n       */\n      if (this.serializationCheck == null) {\n        final ResultLoader old = this.resultLoader;\n        this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement,\n            old.parameterObject, old.targetType, old.cacheKey, old.boundSql);\n      }\n\n      this.metaResultObject.setValue(property, this.resultLoader.loadResult());\n    }\n\n    private Configuration getConfiguration() {\n      if (this.configurationFactory == null) {\n        throw new ExecutorException(\"Cannot get Configuration as configuration factory was not set.\");\n      }\n\n      Object configurationObject;\n      try {\n        final Method factoryMethod = this.configurationFactory.getDeclaredMethod(FACTORY_METHOD);\n        if (!Modifier.isStatic(factoryMethod.getModifiers())) {\n          throw new ExecutorException(\"Cannot get Configuration as factory method [\" + this.configurationFactory + \"]#[\"\n              + FACTORY_METHOD + \"] is not static.\");\n        }\n\n        if (!factoryMethod.canAccess(null)) {\n          configurationObject = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {\n            try {\n              factoryMethod.setAccessible(true);\n              return factoryMethod.invoke(null);\n            } finally {\n              factoryMethod.setAccessible(false);\n            }","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/loader/ResultLoaderMap.java#L209-L245","documentation":"Thrown when MyBatis must rebuild the lazy-loading machinery of a deserialized object but the configurationFactory was never set. Because LoadPair is serialized without the live Configuration, the only way to get it back is a user-supplied factory class; if lazyLoadingEnabled is true but configurationFactory is omitted in the mybatis-config settings, this fails.","triggerScenarios":"A deserialized lazy-loading proxy has load(userObject) called (metaResultObject/resultLoader null), mappedParameter non-null, and LoadPair.getConfiguration() finds this.configurationFactory == null, i.e. <setting name='lazyLoadingEnabled' value='true'/> without <setting name='configurationFactory' value='...'/>.","commonSituations":"Enabling lazy loading for serializable result objects (session replication, distributed caches) but forgetting the configurationFactory setting; configurationFactory silently not serialized because the parameter object was not Serializable so the field was never populated.","solutions":["Add <setting name=\"configurationFactory\" value=\"com.example.MyConfigFactory\"/> to the <settings> block of mybatis-config.xml","Ensure the factory class has a public static Configuration getConfiguration() method returning the live SqlSessionFactory's Configuration","Pre-load lazy properties before serialization so no Configuration rebuild is needed","Make the statement parameter object Serializable so the LoadPair actually records the factory at build time"],"exampleFix":"<!-- before -->\n<settings>\n  <setting name=\"lazyLoadingEnabled\" value=\"true\"/>\n</settings>\n<!-- after -->\n<settings>\n  <setting name=\"lazyLoadingEnabled\" value=\"true\"/>\n  <setting name=\"configurationFactory\" value=\"com.example.MyBatisConfigFactory\"/>\n</settings>","handlingStrategy":"validation","validationCode":"// At startup, fail fast if lazy loading is on but the factory is unset\nConfiguration cfg = sqlSessionFactory.getConfiguration();\nif (cfg.isLazyLoadingEnabled() && cfg.getConfigurationFactory() == null) {\n  throw new IllegalStateException(\"Set configurationFactory when lazyLoadingEnabled=true\");\n}","typeGuard":null,"tryCatchPattern":"try { lazyObj.getLazyProp(); } catch (ExecutorException e) { if (e.getMessage().contains(\"configuration factory was not set\")) { log.error(\"Config error: add configurationFactory setting\", e); } throw e; }","preventionTips":["Treat lazyLoadingEnabled and configurationFactory as one unit in config reviews","Add a startup assertion for the settings pair","Document the factory convention in the project's config template"],"tags":["mybatis","lazy-loading","configuration","serialization"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}