apache/flink · error · RuntimeException

Unable to clone instance of %s.

Error message

Unable to clone instance of %s.

What it means

InstantiationUtil.cloneUnchecked clones a Serializable object by serializing it to a byte array and deserializing it with its classloader. If either the serialization or deserialization step fails (IOException), or the object's class cannot be found during deserialization (ClassNotFoundException), this RuntimeException is thrown, naming the class that failed to clone. It is the unchecked equivalent of clone(Serializable) and is heavily used by the runtime to copy function and configuration objects.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java:589

            return null;
        } else {
            final byte[] serializedObject = serializeObject(obj);
            return deserializeObject(serializedObject, classLoader);
        }
    }

    /**
     * Unchecked equivalent of {@link #clone(Serializable)}.
     *
     * @param obj Object to clone
     * @param <T> Type of the object to clone
     * @return The cloned object
     */
    public static <T extends Serializable> T cloneUnchecked(T obj) {
        try {
            return clone(obj, obj.getClass().getClassLoader());
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(
                    String.format("Unable to clone instance of %s.", obj.getClass().getName()), e);
        }
    }

    /**
     * Clones the given writable using the {@link IOReadableWritable serialization}.
     *
     * @param original Object to clone
     * @param <T> Type of the object to clone
     * @return Cloned object
     * @throws IOException Thrown is the serialization fails.
     */
    public static <T extends IOReadableWritable> T createCopyWritable(T original)
            throws IOException {
        if (original == null) {
            return null;
        }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Inspect the cause chain: the wrapped IOException/ClassNotFoundException names what actually broke (a specific field's class is the usual culprit).
  2. Make every field of the target class Serializable or mark non-serializable fields transient and reinitialize them in readObject/writeReplace.
  3. Ensure the object's class and all nested classes are visible to the classloader passed to clone (obj.getClass().getClassLoader()).
  4. Fix serialVersionUID mismatches between the class version that wrote and read the bytes.
  5. As a workaround for avro-like cases, use a copy constructor or a dedicated clone routine instead of serialization-based cloning.

Example fix

// before
public class MyFunction extends RichMapFunction<String,String> {
    private Connection db; // not serializable -> cloneUnchecked fails
}

// after
public class MyFunction extends RichMapFunction<String,String> {
    private transient Connection db;

    @Override
    public void open(Configuration parameters) {
        db = DriverManager.getConnection(url); // reinitialize after cloning
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify serializability before the runtime clones the object
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(bos)) {
    oos.writeObject(obj);
    oos.flush();
} catch (IOException e) {
    throw new IllegalStateException("obj is not safely serializable: " + e.getMessage(), e);
}

Try / catch

// Prefer the checked API and decide policy explicitly
try {
    T copy = InstantiationUtil.clone(obj, cl);
} catch (IOException | ClassNotFoundException e) {
    // log class name, fall back to manual copy constructor
}

Prevention

When it happens

Trigger: Calling InstantiationUtil.cloneUnchecked(obj) (directly or indirectly, e.g. when the runtime clones a user function) where obj or an object reachable from it is not truly serializable, its class is not visible to obj.getClass().getClassLoader(), a transient/NoSerialize path throws in writeObject/readObject, or a custom serialVersionUID mismatch breaks deserialization.

Common situations: A user function holds a non-serializable field (e.g. a raw Connection, Thread, or logger-like object) that only fails when the runtime deep-clones it; classes loaded in a child-first classloader that cannot be resolved during deserialization; nested objects whose classes were shaded or relocated between versions.

Related errors


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