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

  1. Read the wrapped IOException - it identifies which field/object failed to serialize
  2. Make every field of the copied type Serializable or Kryo-serializable, or mark non-serializable fields transient and reinitialize them
  3. Give the class a public no-arg constructor so kryo.copy() succeeds and the fallback is never needed
  4. Register the class with a stable registration id in the Kryo registrar instead of relying on class-name mode
  5. 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

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


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/a8dbdfb21a8ef21d. Report an issue: GitHub.