mybatis/mybatis-3 · error · ClassNotFoundException

Cannot find class: {}

Error message

Cannot find class: {}

What it means

ClassLoaderWrapper tries to load a class through a chain of classloaders (given loader, defaultClassLoader, context loader, mybatis's own loader, system loader); only after every one fails with ClassNotFoundException does it rethrow as 'Cannot find class: <name>'. Callers typically wrap this into their own exceptions (e.g. type alias or typeHandler resolution failures).

Source

Thrown at src/main/java/org/apache/ibatis/io/ClassLoaderWrapper.java:226

  Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {

    for (ClassLoader cl : classLoader) {

      if (null != cl) {

        try {

          return Class.forName(name, true, cl);

        } catch (ClassNotFoundException e) {
          // we'll ignore this until all classloaders fail to locate the class
        }

      }

    }

    throw new ClassNotFoundException("Cannot find class: " + name);

  }

  ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[] { classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
        getClass().getClassLoader(), systemClassLoader };
  }

}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Fix the class name string — verify the fully qualified name, use $ for nested classes if needed.
  2. Ensure the containing jar/class is actually on the runtime classpath (not just compile-time).
  3. Set Configuration.setDefaultClassLoader to the application's classloader in container environments.
  4. In hot-reload/dev-restart setups, rebuild so freshly loaded classes are visible to the current context classloader.

Example fix

<!-- before -->
<typeAlias type="com.exmaple.domain.User" alias="User"/> <!-- typo: exmaple -->

<!-- after -->
<typeAlias type="com.example.domain.User" alias="User"/>
Defensive patterns

Strategy: validation

Validate before calling

// validate every alias/type name resolves before building the session
static void checkClassNames(ClassLoader cl, String... names) {
  for (String n : names) {
    try {
      Class.forName(n, true, cl);
    } catch (ClassNotFoundException e) {
      throw new IllegalStateException("Type referenced in mybatis config not loadable: " + n, e);
    }
  }
}

Type guard

static Optional<Class<?>> tryLoad(ClassLoader cl, String fqn) {
  try { return Optional.of(Class.forName(fqn, true, cl)); }
  catch (ClassNotFoundException e) { return Optional.empty(); }
}

Try / catch

catch (PersistenceException | RuntimeException e) when rootCauseIs(e, ClassNotFoundException.class) && e.getMessage().contains("Cannot find class") -> report the class name and current classloader chain; treat as deployment/packaging defect, not retryable.

Prevention

When it happens

Trigger: Resolving a typeAlias, resultType, parameterType, or typeHandler class name from mybatis-config.xml / mapper XML where the named class is absent from every classloader in the chain — typo in the name, class not on the classpath, or isolated/war classloader setups where the class lives in a loader not in the chain.

Common situations: Typos in fully qualified class names in XML; class in a module/jar not included in the deployment; web/app-server deployments where the thread context classloader differs from the app classloader; hot-reload environments with stale loaders; inner classes written with '.' instead of '$' or missing package.

Related errors


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