apache/flink · error · IOException

Unable to serialize default value of type {}.

Error message

Unable to serialize default value of type {}.

What it means

During Java serialization of the StateDescriptor (writeObject), Flink serializes the non-null defaultValue using a duplicate of the descriptor's TypeSerializer. If serializer.serialize(defaultValue, outView) throws (e.g., the value type does not match what the serializer expects, or the serializer implementation has a bug), the exception is wrapped in an IOException with the value's simple class name.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/state/StateDescriptor.java:411

            out.writeBoolean(false);
        } else {
            TypeSerializer<T> serializer = serializerAtomicReference.get();
            checkNotNull(serializer, "Serializer not initialized.");

            // we have a default value
            out.writeBoolean(true);

            byte[] serializedDefaultValue;
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    DataOutputViewStreamWrapper outView = new DataOutputViewStreamWrapper(baos)) {

                TypeSerializer<T> duplicateSerializer = serializer.duplicate();
                duplicateSerializer.serialize(defaultValue, outView);

                outView.flush();
                serializedDefaultValue = baos.toByteArray();
            } catch (Exception e) {
                throw new IOException(
                        "Unable to serialize default value of type "
                                + defaultValue.getClass().getSimpleName()
                                + ".",
                        e);
            }

            out.writeInt(serializedDefaultValue.length);
            out.write(serializedDefaultValue);
        }
    }

    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
        // read the non-transient fields
        in.defaultReadObject();

        // read the default value field
        boolean hasDefaultValue = in.readBoolean();
        if (hasDefaultValue) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure defaultValue's runtime type is exactly the type the descriptor's serializer handles — do not pass a subclass instance as the default.
  2. Test the serializer round-trip on the default value in isolation (serialize/deserialize) before constructing the descriptor.
  3. If using a custom TypeSerializer, verify serialize/deserialize are symmetric and handle the default value.
  4. Avoid setting a default value of a type that the serializer cannot represent; pass null instead and handle missing-state logic in the function.

Example fix

// before
new ValueStateDescriptor<>("n", MyPojo.class, new MyPojoSubclass()); // type mismatch

// after
new ValueStateDescriptor<>("n", MyPojo.class, new MyPojo());
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify the default value type matches the descriptor's type before assigning
T defaultValue = ...;
if (!descriptorTypeClass.isInstance(defaultValue)) {
    throw new IllegalArgumentException("Default value type mismatch");
}
// Round-trip test the serializer on the default value
TypeSerializer<T> ser = descriptor.getTypeInformation().createSerializer(cfg);
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
    ser.serialize(defaultValue, new DataOutputViewStreamWrapper(out));
    T copy = ser.deserialize(new DataInputViewStreamWrapper(
        new ByteArrayInputStream(out.toByteArray())));
}

Type guard

// Ensure defaultValue is exactly the serializer's type
Class<?> t = descriptor.getTypeInformation().getTypeClass();
if (!t.isInstance(defaultValue)) {
    throw new ClassCastException(defaultValue + " is not a " + t);
}

Try / catch

// Serialization happens during job graph distribution; catch in tests, not in prod.
try {
    env.execute(); // triggers descriptor serialization
} catch (Exception e) {
    if (e.getCause() instanceof IOException
        && e.getMessage().contains("Unable to serialize default value")) {
        // fix the default value type and rebuild
    }
}

Prevention

When it happens

Trigger: The defaultValue was set with an instance whose runtime type differs from the serializer's T (e.g., assigning a subclass the serializer cannot handle); a custom TypeSerializer that fails on a particular value; serializing a descriptor whose serializer and default value were configured inconsistently.

Common situations: Distributing the job graph (Java serialization of descriptors to TaskManagers); checkpointing the descriptor; a default value set via a builder that bypasses type checks; upgrading a serializer snapshot while the in-memory default value is stale.

Related errors


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