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

  1. Add the missing class (name in the message) back to the classpath or restore its original package name
  2. Ensure the thread context classloader used by ObjectInputStream can load the class (Thread.currentThread().setContextClassLoader(...))
  3. Invalidate the serializedDataCache so fresh bytes are generated from loadable classes
  4. 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

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


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)