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
- Fix the class name string — verify the fully qualified name, use $ for nested classes if needed.
- Ensure the containing jar/class is actually on the runtime classpath (not just compile-time).
- Set Configuration.setDefaultClassLoader to the application's classloader in container environments.
- 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
- Run a config-validation test at build time that resolves every resultType/parameterType/typeHandler named in XML.
- Use $ for nested classes in XML type names and verify jars are in the runtime, not just compile, classpath.
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
- Error setting driver on UnpooledDataSource.
- Could not find resource {}
- Error setting Log implementation. Cause: {}
- Could not resolve type alias '{}'. Cause: {}
- Error registering type alias {} for {}. Cause: {}
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/8200540a8d5c675f.
Report an issue: GitHub.