apache/flink · error · RuntimeException
Could not copy object by serializing/deserializing it.
Error message
Could not copy object by serializing/deserializing it.
What it means
KryoUtils.copy(from, kryo, serializer) first tries kryo.copy(from); if Kryo cannot copy (KryoException), it falls back to serialize/deserialize via the provided TypeSerializer. This error means both paths failed: the IOException from InstantiationUtil.serializeToByteArray/deserializeFromByteArray is wrapped in this RuntimeException.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/KryoUtils.java:56
* record from is copied by serializing it into a byte buffer and deserializing it from there.
*
* @param from Element to copy
* @param kryo Kryo instance to use
* @param serializer TypeSerializer which is used in case of a Kryo failure
* @param <T> Type of the element to be copied
* @return Copied element
*/
public static <T> T copy(T from, Kryo kryo, TypeSerializer<T> serializer) {
try {
return kryo.copy(from);
} catch (KryoException ke) {
// Kryo could not copy the object --> try to serialize/deserialize the object
try {
byte[] byteArray = InstantiationUtil.serializeToByteArray(serializer, from);
return InstantiationUtil.deserializeFromByteArray(serializer, byteArray);
} catch (IOException ioe) {
throw new RuntimeException(
"Could not copy object by serializing/deserializing" + " it.", ioe);
}
}
}
/**
* Tries to copy the given record from using the provided Kryo instance. If this fails, then the
* record from is copied by serializing it into a byte buffer and deserializing it from there.
*
* @param from Element to copy
* @param reuse Reuse element for the deserialization
* @param kryo Kryo instance to use
* @param serializer TypeSerializer which is used in case of a Kryo failure
* @param <T> Type of the element to be copied
* @return Copied element
*/
public static <T> T copy(T from, T reuse, Kryo kryo, TypeSerializer<T> serializer) {
try {View on GitHub (pinned to 2f3c205e92)
Solutions
- Read the wrapped IOException - it identifies which field/object failed to serialize
- Make every field of the copied type Serializable or Kryo-serializable, or mark non-serializable fields transient and reinitialize them
- Give the class a public no-arg constructor so kryo.copy() succeeds and the fallback is never needed
- Register the class with a stable registration id in the Kryo registrar instead of relying on class-name mode
- If state restore is involved, ensure the serializer's snapshot version matches the data being read
Example fix
// before
class SessionState {
Connection conn; // not serializable
}
// after
class SessionState implements Serializable {
transient Connection conn; // re-opened in open()
String sessionId;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before copying, verify the type can round-trip through the serializer
try {
InstantiationUtil.serializeToByteArray(serializer, sampleElement);
} catch (IOException e) {
throw new IllegalStateException("Element is not serializable: " + e, e);
} Type guard
static boolean isKryoCopyable(Class<?> c) {
try {
c.getDeclaredConstructor().setAccessible(true);
return true;
} catch (ReflectiveOperationException e) {
return false;
}
} Try / catch
try {
T copy = KryoUtils.copy(from, kryo, serializer);
} catch (RuntimeException e) {
// both kryo.copy and serialize/deserialize failed
throw new IllegalStateException("Cannot copy element of " + from.getClass(), e.getCause());
} Prevention
- Give classes used in state a public no-arg constructor so kryo.copy() succeeds
- Keep all fields Serializable or transient+reinitialized
- Register custom types with stable Kryo registration ids
When it happens
Trigger: Calling KryoUtils.copy during operator chaining, iteractive/feedback streams, or session windowing state copies; Kryo copy fails (no accessible constructor / unregistered class), then serialization fails because the object graph contains a non-serializable field or the serializer snapshot is incompatible.
Common situations: A custom class used as a key or in managed state has a non-serializable field (e.g. an open connection, Thread, or lambda); Kryo registration ids changed between job submissions while restoring state; a custom TypeSerializer that throws on serialize; deep object graphs exceeding Kryo's max depth.
Related errors
- Failed to serialize value '{value}'
- Cannot register null class or serializer.
- Unexpected serializer type.
- Corrupt data, magic number mismatch. Expected %8x, found %8x
- Undefined compatibility type.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/a8dbdfb21a8ef21d.
Report an issue: GitHub.