apache/flink · critical · IllegalStateException
Unable to find the class '%s' which is used to deserialize t
Error message
Unable to find the class '%s' which is used to deserialize the elements of this serializer. Were the class was moved or renamed?
What it means
IllegalStateException from AvroSerializerSnapshot.findClassOrThrow when Class.forName cannot load the Avro record class (or SpecificRecord) referenced by the restored state. The serializer snapshot stores the runtime class name; on restore it must be loadable from the user code classloader of the restored job.
Source
Thrown at flink-formats/flink-avro/src/main/java/org/apache/flink/formats/avro/typeutils/AvroSerializerSnapshot.java:236
@SuppressWarnings("unchecked")
SpecificData d =
AvroFactory.getSpecificDataForClass(
(Class<? extends SpecificData>) runtimeType, cl);
return AvroFactory.extractAvroSpecificSchema(runtimeType, d);
}
ReflectData d = new ReflectData(cl);
return d.getSchema(runtimeType);
}
@SuppressWarnings("unchecked")
@Nonnull
private static <T> Class<T> findClassOrThrow(
ClassLoader userCodeClassLoader, String className) {
try {
Class<?> runtimeTarget = Class.forName(className, false, userCodeClassLoader);
return (Class<T>) runtimeTarget;
} catch (ClassNotFoundException e) {
throw new IllegalStateException(
""
+ "Unable to find the class '"
+ className
+ "' which is used to deserialize "
+ "the elements of this serializer. "
+ "Were the class was moved or renamed?",
e);
}
}
@SuppressWarnings("unchecked")
@Nonnull
private static <T> Class<T> findClassOrFallbackToGeneric(
ClassLoader userCodeClassLoader, String className) {
try {
Class<?> runtimeTarget = Class.forName(className, false, userCodeClassLoader);
return (Class<T>) runtimeTarget;
} catch (ClassNotFoundException e) {View on GitHub (pinned to 2f3c205e92)
Solutions
- Keep the fully-qualified class name of Avro records stable across job versions (regenerate code into the same package).
- Repackage the jar so the record class is included on the user classpath and not shaded away.
- If rename is unavoidable, perform a state migration (savepoint processor API) instead of direct restore.
Defensive patterns
Strategy: validation
Validate before calling
// before restore, verify the record class is on the job classpath
Class<?> c = Class.forName("com.acme.avro.User", false, getUserClassloader());
if (!org.apache.avro.specific.SpecificRecordBase.class.isAssignableFrom(c)) {
throw new IllegalStateException("Restored Avro class is not a SpecificRecord");
} Try / catch
try {
env.execute();
} catch (IllegalStateException e) {
if (e.getMessage().contains("Unable to find the class")) {
// class moved/missing from jar; fix packaging or class name, then restore again
log.error("Avro record class missing on user classpath: {}", e.getCause().getMessage());
}
throw e;
} Prevention
- Freeze the package name of generated Avro classes across job versions.
- Add a CI check that the fat jar contains every class named in the state's serializer snapshots.
- Avoid shading/relocating generated Avro record packages in stateful jobs.
When it happens
Trigger: Restoring a savepoint after the Avro generated record class was renamed, moved to another package, or removed from the job jar; running with a fat jar that shades/relocates the record class.
Common situations: Refactoring generated Avro classes between job versions; maven-shade relocation of avro generated packages; the class living in a dependency not packaged into the application jar.
Related errors
- Could not access the MODEL$ field of avro record
- Failed to Java-Deserialize an AvroSerializer instance. Was e
- unknown snapshot version for AvroSerializerSnapshot %s
- Could not find any format factory for identifier '%s' in the
- Could not find any format factory for identifier '%s' in the
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/12a66f60a186b0b1.
Report an issue: GitHub.