apache/flink · error · IllegalStateException

Serializer not yet initialized.

Error message

Serializer not yet initialized.

What it means

getDefaultValue() tries to return a defensive copy of the default value via serializer.copy(defaultValue), but the serializer reference inside the StateDescriptor is still null because initializeSerializerUnlessSet(ExecutionConfig) has not been called yet. The descriptor holds the raw defaultValue but cannot safely hand it back without a serializer to copy it. Flink initializes serializers lazily so they can pick up ExecutionConfig settings (e.g., Pojo field registration).

Source

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

        this.defaultValue = defaultValue;
    }

    // ------------------------------------------------------------------------

    /** Returns the name of this {@code StateDescriptor}. */
    public String getName() {
        return name;
    }

    /** Returns the default value. */
    public T getDefaultValue() {
        if (defaultValue != null) {
            TypeSerializer<T> serializer = serializerAtomicReference.get();
            if (serializer != null) {
                return serializer.copy(defaultValue);
            } else {
                throw new IllegalStateException("Serializer not yet initialized.");
            }
        } else {
            return null;
        }
    }

    /**
     * Returns the {@link TypeSerializer} that can be used to serialize the value in the state. Note
     * that the serializer may initialized lazily and is only guaranteed to exist after calling
     * {@link #initializeSerializerUnlessSet(ExecutionConfig)}.
     */
    public TypeSerializer<T> getSerializer() {
        TypeSerializer<T> serializer = serializerAtomicReference.get();
        if (serializer != null) {
            return serializer.duplicate();
        } else {
            throw new IllegalStateException("Serializer not yet initialized.");
        }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Call descriptor.initializeSerializerUnlessSet(executionConfig) before invoking getDefaultValue, using the ExecutionConfig available from the RuntimeContext or StreamExecutionEnvironment.
  2. Restructure code to read the default value lazily after the runtime has opened the state, not at descriptor-construction time.
  3. In tests, pass a new ExecutionConfig() (or the one from StreamExecutionEnvironment) to initializeSerializerUnlessSet before asserting on the default.

Example fix

// before
ValueStateDescriptor<Long> desc = new ValueStateDescriptor<>("c", Long.class, 0L);
Long def = desc.getDefaultValue(); // throws

// after
ValueStateDescriptor<Long> desc = new ValueStateDescriptor<>("c", Long.class, 0L);
desc.initializeSerializerUnlessSet(env.getConfig());
Long def = desc.getDefaultValue();
Defensive patterns

Strategy: validation

Validate before calling

// Check serializer initialization before reading the default value
if (descriptor.isSerializerInitialized()) {
    T def = descriptor.getDefaultValue();
} else {
    descriptor.initializeSerializerUnlessSet(executionConfig);
    T def = descriptor.getDefaultValue();
}

Type guard

// v1 StateDescriptor exposes isSerializerInitialized()
if (!stateDescriptor.isSerializerInitialized()) {
    stateDescriptor.initializeSerializerUnlessSet(
        getRuntimeContext().getExecutionConfig());
}

Try / catch

// Prefer validation over try-catch; IllegalStateException means a lifecycle bug.
try {
    return descriptor.getDefaultValue();
} catch (IllegalStateException e) {
    descriptor.initializeSerializerUnlessSet(executionConfig);
    return descriptor.getDefaultValue();
}

Prevention

When it happens

Trigger: Calling stateDescriptor.getDefaultValue() in user code or a test before the descriptor has been wired through initializeSerializerUnlessSet, or constructing a descriptor with a TypeInformation but never passing an ExecutionConfig before reading the default.

Common situations: Unit tests that build a descriptor and immediately assert on the default value; calling getDefaultValue inside an open() method that runs before the runtime has initialized the descriptor; a custom operator that holds a descriptor but skips the initialization hook.

Related errors


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