mybatis/mybatis-3 · error · CacheException
Error deserializing object. Cause: ${cause}
Error message
Error deserializing object. Cause: ${cause} What it means
Thrown by SerializedCache.deserialize() when converting the cached byte[] back into an object fails: class not found on deserialization (stale cache across a redeploy), stream corruption, serialVersionUID mismatch, or a JEP 290 filter rejection. Note the entry point runs SerialFilterChecker.check() first and the actual read happens inside CustomObjectInputStream, so class-loading and filter failures surface here.
Source
Thrown at src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java:105
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 {
super(in);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
return Resources.classForName(desc.getName());
}
}
}View on GitHub (pinned to 008069adb1)
Solutions
- Clear/flush the second-level cache after deployments that change entity classes (or version the cache keys with an app version prefix)
- Declare explicit serialVersionUID on cached types to survive compatible field changes
- Align JEP 290 filter configuration with the classes you intentionally cache; evict the offending key and retry
Example fix
// before: stale entry from previous deploy -> InvalidClassException // after: cache keys namespaced by app version cacheKeyPrefix = "app:v42:"; // bump on entity changes -> old entries never deserialized
Defensive patterns
Strategy: fallback
Validate before calling
null
Try / catch
catch (CacheException e) { if (e.getCause() instanceof InvalidClassException || e.getCause() instanceof ClassNotFoundException) { evict(key); return loadFromDatabaseAndRepopulate(); } throw e; } Prevention
- Version cache keys per deployment to avoid stale entries
- Declare serialVersionUID on cached types
- Flush distributed caches during rolling deploys
When it happens
Trigger: Reading a second-level cache entry (getObject) whose bytes were written by a previous deployment: entity class renamed/moved (ClassNotFoundException), class evolved without compatible serialVersionUID (InvalidClassException), cache storage (e.g. Redis/Ehcache disk) surviving application restarts, or deserialization filters blocking a class.
Common situations: Rolling deploys with a shared distributed cache where old-format entries linger; JDK upgrades tightening ObjectInputFilter defaults; repackaging entities to a new module/package; corrupted entries after a network cache hiccup.
Related errors
- SharedCache failed to make a copy of a non-serializable obje
- Error serializing object. Cause: ${cause}
- Caching stored procedures with OUT params is not supported.
- Cannot lazy load property [" + this.property + "] of deseria
- Unknown execution method for: {name}
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/73da14808418d929.
Report an issue: GitHub.