{"record":{"id":"417cba677147a3a9","repo":"mybatis/mybatis-3","slug":"error-creating-lazy-proxy-cause-e","errorCode":null,"errorMessage":"Error creating lazy proxy.  Cause: \" + e","messagePattern":"Error creating lazy proxy\\.  Cause: \" \\+ e","errorType":"exception","errorClass":"ExecutorException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/executor/loader/javassist/JavassistProxyFactory.java","lineNumber":97,"sourceCode":"    try {\n      type.getDeclaredMethod(WRITE_REPLACE_METHOD);\n      // ObjectOutputStream will call writeReplace of objects returned by writeReplace\n      if (LogHolder.log.isDebugEnabled()) {\n        LogHolder.log.debug(WRITE_REPLACE_METHOD + \" method was found on bean \" + type + \", make sure it returns this\");\n      }\n    } catch (NoSuchMethodException e) {\n      enhancer.setInterfaces(new Class[] { WriteReplaceInterface.class });\n    } catch (SecurityException e) {\n      // nothing to do here\n    }\n\n    Object enhanced;\n    Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);\n    Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);\n    try {\n      enhanced = enhancer.create(typesArray, valuesArray);\n    } catch (Exception e) {\n      throw new ExecutorException(\"Error creating lazy proxy.  Cause: \" + e, e);\n    }\n    ((Proxy) enhanced).setHandler(callback);\n    return enhanced;\n  }\n\n  private static class EnhancedResultObjectProxyImpl implements MethodHandler {\n    private final Class<?> type;\n    private final ResultLoaderMap lazyLoader;\n    private final boolean aggressive;\n    private final Set<String> lazyLoadTriggerMethods;\n    private final ObjectFactory objectFactory;\n    private final List<Class<?>> constructorArgTypes;\n    private final List<Object> constructorArgs;\n    private final ReentrantLock lock = new ReentrantLock();\n\n    private EnhancedResultObjectProxyImpl(Class<?> type, ResultLoaderMap lazyLoader, Configuration configuration,\n        ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {\n      this.type = type;","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/executor/loader/javassist/JavassistProxyFactory.java#L79-L115","documentation":"JavassistProxyFactory.createEnhancedInstance calls enhancer.create(typesArray, valuesArray) to build the lazy-loading subclass of your domain object; any exception from Javassist during bytecode generation/instantiation is wrapped in this ExecutorException ('Error creating lazy proxy. Cause: ...'). Common underlying causes are final classes/methods that cannot be enhanced, constructor mismatch, or classloader issues in hot-deploy environments.","triggerScenarios":"lazyLoadingEnabled=true and a result class that Javassist cannot subclass: declared final, or whose constructor signature does not match the recorded constructorArgTypes/constructorArgs; also classloader leaks after repeated redeploys where the enhanced class cannot be defined.","commonSituations":"Kotlin data classes or Java classes marked final (Java 17+ strongly encourages final); domain classes without a no-arg (or matching) constructor; Tomcat hot redeploy producing LinkageError inside enhancer.create; abstract types used as resultType.","solutions":["Un-final the result class (and its methods) so Javassist can subclass it — remove 'final' from the class declaration","Add a public no-arg constructor to the result class","On classloader-heavy apps, disable lazy loading or reuse a single classloader to avoid re-enhancement LinkageErrors","Check the nested 'Cause:' in the message — it identifies the exact Javassist failure (final method, abstract class, etc.)"],"exampleFix":"// before\npublic final class Order {          // cannot be enhanced\n  public Order(Long id) { ... }      // no no-arg ctor\n}\n// after\npublic class Order {\n  public Order() {}\n  public Order(Long id) { ... }\n}","handlingStrategy":"validation","validationCode":"// Guard result classes used with lazy loading: subclassable + instantiable\nClass<?> c = Order.class;\nint mods = c.getModifiers();\nif (Modifier.isFinal(mods)) throw new IllegalStateException(c + \" must not be final for lazy loading\");\ntry { c.getDeclaredConstructor().newInstance(); } catch (ReflectiveOperationException e) { throw new IllegalStateException(c + \" needs a public no-arg constructor\", e); }","typeGuard":"static boolean isLazyProxyable(Class<?> c) { return !Modifier.isFinal(c.getModifiers()) && !Modifier.isAbstract(c.getModifiers()); }","tryCatchPattern":"try { session.selectList(\"sel.orders\"); } catch (ExecutorException e) { if (e.getMessage() != null && e.getMessage().contains(\"Error creating lazy proxy\")) { log.error(\"Result class not proxyable: \" + e.getCause()); } throw e; }","preventionTips":["Keep lazy-loaded entity classes non-final with a no-arg constructor (or open in Kotlin)","Read the nested Cause to find the exact enhancement failure","Avoid hot-redeploy loops that leak enhanced classes"],"tags":["mybatis","lazy-loading","javassist","bytecode","proxy"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}