MyCATApache/Mycat-Server · error · ObjectAccessException

Cannot create by JDK serialization

Error message

Cannot create ${type} by JDK serialization

What it means

instantiateUsingSerialization creates an instance of a type via JDK serialization: it writes an empty instance's serialized form and reads it back to bypass missing constructors. If an IOException occurs during that readObject, the provider throws ObjectAccessException 'Cannot create <type> by JDK serialization'. This usually means the target class is not actually serializable-compatible at that moment or the cached data is corrupt.

Solutions

  1. Confirm the target class implements Serializable and defines a stable serialVersionUID
  2. Clear/rebuild the serializedDataCache after upgrading the class
  3. Ensure the class's no-arg constructor (for Externalizable) does not throw
  4. If the class cannot be JDK-serialized, provide a working constructor path instead of newInstance-serialization
  5. Read e.getCause() for the underlying stream/serialization reason

Example fix

// before
class ConfigPoint { private String name; } // no serialVersionUID
// after
class ConfigPoint implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before instantiation
if (!(Serializable.class.isAssignableFrom(type))) {
    throw new IllegalArgumentException(type + " is not Serializable");
}
long svuid = type.getDeclaredField("serialVersionUID").getLong(null); // verify stable UID

Try / catch

try {
    Object o = provider.newInstance(type);
} catch (ObjectAccessException e) {
    // clear cache and retry once
    Object o2 = provider.newInstance(type);
}

Prevention

When it happens

Trigger: ObjectInputStream.readObject throws IOException because the class's serialized form changed (serialVersionUID mismatch), the class is Externalizable with a failing no-arg constructor, or the cached serialized byte[] is truncated/corrupt.

Common situations: Deserializing a class whose serialVersionUID changed after a library upgrade; class not implementing Serializable but routed through this path; corrupt cached bytes in serializedDataCache.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11). Data as JSON: /api/errors/5536cdf02408943b. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/config/util/ReflectionProvider.java:167

                DataOutputStream stream = new DataOutputStream(bytes);
                stream.writeShort(ObjectStreamConstants.STREAM_MAGIC);
                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)