MyCATApache/Mycat-Server · error · ObjectAccessException
Cannot find class
Error message
Cannot find class ${className} What it means
During JDK-serialization-based instantiation, ObjectInputStream.readObject throws ClassNotFoundException when a class referenced in the serialized stream cannot be loaded by the current classloader. The provider converts it into ObjectAccessException 'Cannot find class <name>', where <name> comes from e.getMessage().
Solutions
- Add the missing class (name in the message) back to the classpath or restore its original package name
- Ensure the thread context classloader used by ObjectInputStream can load the class (Thread.currentThread().setContextClassLoader(...))
- Invalidate the serializedDataCache so fresh bytes are generated from loadable classes
- Check for serialVersionUID/name mismatches after dependency upgrades
Example fix
// before ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)); // data references moved class // after Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader()); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data));
Defensive patterns
Strategy: try-catch
Validate before calling
// verify all classes referenced by cached serialized bytes are loadable Thread.currentThread().setContextClassLoader(type.getClassLoader()); Class.forName(expectedClassName, true, type.getClassLoader());
Try / catch
try {
Object o = provider.newInstance(type);
} catch (ObjectAccessException e) {
if (e.getMessage().startsWith("Cannot find class")) {
Thread.currentThread().setContextClassLoader(type.getClassLoader());
Object o2 = provider.newInstance(type);
}
} Prevention
- Keep the thread context classloader aligned with the app classloader
- Avoid renaming/moving serialized classes between releases
- Purge serialized caches on dependency upgrades
- Pin serialVersionUIDs to reduce stream/class drift
When it happens
Trigger: readObject encounters a class in the byte stream that is not on the classpath or is not loadable by the thread/context classloader (e.g. class renamed/moved between versions, different classloader in app-server).
Common situations: Upgrading mycat or a dependency so a serialized class's package/name changed; deploying in a servlet container where the webapp classloader cannot see the class; typo'd or removed class referenced in cached serialized data.
Related errors
- Cannot create by JDK serialization
- Could not get field .
- No such field .
- rule function must implements
- Tried to send an out-of-range integer as a 2-byte value
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/e048f59f80c2742e.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/config/util/ReflectionProvider.java:169
stream.writeShort(ObjectStreamConstants.STREAM_VERSION);
stream.writeByte(ObjectStreamConstants.TC_OBJECT);
stream.writeByte(ObjectStreamConstants.TC_CLASSDESC);
stream.writeUTF(type.getName());
stream.writeLong(ObjectStreamClass.lookup(type).getSerialVersionUID());
stream.writeByte(2); // classDescFlags (2 = Serializable)
stream.writeShort(0); // field count
stream.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
stream.writeByte(ObjectStreamConstants.TC_NULL);
data = bytes.toByteArray();
serializedDataCache.put(type, data);
}
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data));
return in.readObject();
} catch (IOException e) {
throw new ObjectAccessException("Cannot create " + type.getName() + " by JDK serialization", e);
} catch (ClassNotFoundException e) {
throw new ObjectAccessException("Cannot find class " + e.getMessage());
}
}
private boolean fieldModifiersSupported(Field field) {
return !(Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers()));
}
private void validateFieldAccess(Field field) {
if (Modifier.isFinal(field.getModifiers())) {
if (JVMInfo.is15()) {
field.setAccessible(true);
} else {
throw new ObjectAccessException("Invalid final field " + field.getDeclaringClass().getName() + "."
+ field.getName());
}
}
}
View on GitHub (pinned to 65f8d8beb7)