mybatis/mybatis-3 · error · CacheException
Error serializing object. Cause: ${cause}
Error message
Error serializing object. Cause: ${cause} What it means
Thrown by SerializedCache.serialize() when Java ObjectOutputStream fails while converting a cached value to bytes: the object passed the instanceof Serializable check but serialization itself errored (a nested non-serializable field, a Serializable class whose writeObject throws, or an I/O failure inside the stream). The original exception is chained as the cause and mirrored in the message.
Source
Thrown at src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java:94
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
private byte[] serialize(Serializable value) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(value);
oos.flush();
return bos.toByteArray();
} catch (Exception e) {
throw new CacheException("Error serializing object. Cause: " + e, e);
}
}
private Serializable deserialize(byte[] value) {
SerialFilterChecker.check();
Serializable result;
try (ByteArrayInputStream bis = new ByteArrayInputStream(value);
ObjectInputStream ois = new CustomObjectInputStream(bis)) {
result = (Serializable) ois.readObject();
} catch (Exception e) {
throw new CacheException("Error deserializing object. Cause: " + e, e);
}
return result;
}
public static class CustomObjectInputStream extends ObjectInputStream {
public CustomObjectInputStream(InputStream in) throws IOException {View on GitHub (pinned to 008069adb1)
Solutions
- Inspect the cause: NotSerializableException names the exact offending class — make that class Serializable or mark the field transient
- Remove non-data fields from cached result types, or map them with a typeHandler that stores a serializable representation
- Check JEP 290 serialization filters / SerialFilterChecker constraints if classes are being rejected by policy
Example fix
// before
public class Order implements Serializable {
private transient OrderStateListener listener; // was NOT transient -> NotSerializableException
}
// after
public class Order implements Serializable {
private transient OrderStateListener listener;
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight in tests: round-trip the entity new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(sampleEntity); // throws NotSerializableException naming the field type
Type guard
static boolean safelySerializable(Object o) { try { serialize(o); return true; } catch (Exception e) { return false; } } Try / catch
catch (CacheException e) { if (e.getCause() instanceof NotSerializableException) { mark type non-cacheable / disable cache for that mapper and log; } else throw e; } Prevention
- Round-trip test every cached entity type in CI
- Mark infrastructure fields transient
- Watch JEP 290 filters on newer JDKs
When it happens
Trigger: Caching an object whose top-level class implements Serializable but a field's type does not (NotSerializableException deep in the graph); a custom writeObject/readObject throwing; graph cycles or StackOverflowError during serialization of deeply nested lazy-loaded proxies.
Common situations: Entities with lazy-loading proxies (mybatis lazy loading wrapped objects) whose enhancer state is not serializable; adding a new field of a library type (e.g. java.lang.Thread, an InputStream wrapper) to a cached entity; serialization filters (JEP 290) rejecting a class in newer JDKs.
Related errors
- SharedCache failed to make a copy of a non-serializable obje
- Error deserializing object. Cause: ${cause}
- Caching stored procedures with OUT params is not supported.
- Cannot lazy load property [" + this.property + "] of deseria
- Cannot get Configuration as configuration factory was not se
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/879640aa30ebf2fc.
Report an issue: GitHub.