apache/flink · error · KryoException
Error during Java deserialization.
Error message
Error during Java deserialization.
What it means
JavaSerializer.read() is the deserialization half of the Kryo-to-Java serialization bridge. It lazily builds an InstantiationUtil.ClassLoaderObjectInputStream over Kryo's Input (using Kryo's classloader) and calls readObject(). Any failure — class not found under the user classloader, serialVersionUID mismatch, stream corruption, or a readObject method throwing — is rethrown as KryoException 'Error during Java deserialization.'.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/kryo/JavaSerializer.java:82
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public T read(Kryo kryo, Input input, Class aClass) {
try {
ObjectMap graphContext = kryo.getGraphContext();
ObjectInputStream objectStream = (ObjectInputStream) graphContext.get(this);
if (objectStream == null) {
// make sure we use Kryo's classloader
objectStream =
new InstantiationUtil.ClassLoaderObjectInputStream(
input, kryo.getClassLoader());
graphContext.put(this, objectStream);
}
return (T) objectStream.readObject();
} catch (Exception ex) {
throw new KryoException("Error during Java deserialization.", ex);
}
}
}
View on GitHub (pinned to 2f3c205e92)
Solutions
- Check the nested cause: ClassNotFoundException means the class is missing from the job's user-code jar — ship it and resubmit.
- Add 'private static final long serialVersionUID = 1L;' to all classes stored in Java-serialized state so refactorings do not break compatibility.
- If the class legitimately changed incompatibly, use state processor API / savepoint migration to rewrite state, or keep a compatible readObject path.
- For corruption issues, verify the same serializer configuration (registered types/order) is used on write and read.
Example fix
// before
public class Event { /* no serialVersionUID */ }
// after
public class Event implements java.io.Serializable {
private static final long serialVersionUID = 1L;
// ...
} Defensive patterns
Strategy: try-catch
Try / catch
try {
T value = kryo.readObject(input, clazz);
} catch (com.esotericsoftware.kryo.KryoException e) {
if (e.getCause() instanceof ClassNotFoundException) {
// missing class in user classloader: fail with class name
} else if (e.getCause() instanceof java.io.InvalidClassException) {
// serialVersionUID mismatch: needs state migration
}
throw e;
} Prevention
- Declare explicit serialVersionUID on every class stored in serialized state.
- Run a canary restore of savepoints in CI after class changes.
- Keep user-code jars self-contained so the TaskManager classloader can resolve all stored classes.
When it happens
Trigger: Restoring a checkpoint/savepoint where a serialized class was renamed, moved packages, or its serialVersionUID changed; the user code classloader on the TaskManager not containing the class; corrupted or truncated buffer being handed to the input stream; a custom readObject implementation throwing.
Common situations: Job upgrade without a stable serialVersionUID; classes loaded from user jars absent from the TaskManager classpath; reading state written by a different Flink or class version; network buffer truncation producing a corrupted ObjectInputStream stream.
Related errors
- Error during Java serialization.
- The Kryo Output still contains data from a previous serializ
- Could not clone serializer instance of class {className}
- Failed to deserialize an element from the source. If you are
- Reached the end of the collection. This could be caused by i
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/0412f41f47122eb6.
Report an issue: GitHub.