apache/flink · error · InvalidTypesException
A TypeInfoFactory for type '{}' is already registered.
Error message
A TypeInfoFactory for type '{}' is already registered. What it means
Thrown by TypeExtractor.registerFactory when a TypeInfoFactory has already been registered for the given Type. The registration is stored in a static ConcurrentHashMap (registeredTypeInfoFactories) keyed by the Type. Attempting to register a second factory for the same Type is rejected to prevent ambiguous type information resolution.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:166
* Registers a type information factory globally for a certain type. Every following type
* extraction operation will use the provided factory for this type. The factory will have the
* highest precedence for this type. In a hierarchy of types the registered factory has higher
* precedence than annotations at the same level but lower precedence than factories defined
* down the hierarchy.
*
* @param t type for which a new factory is registered
* @param factory type information factory that will produce {@link TypeInformation}
*/
@Internal
public static void registerFactory(Type t, Class<? extends TypeInfoFactory<?>> factory) {
Preconditions.checkNotNull(t, "Type parameter must not be null.");
Preconditions.checkNotNull(factory, "Factory parameter must not be null.");
if (!TypeInfoFactory.class.isAssignableFrom(factory)) {
throw new IllegalArgumentException("Class is not a TypeInfoFactory.");
}
if (registeredTypeInfoFactories.containsKey(t)) {
throw new InvalidTypesException(
"A TypeInfoFactory for type '" + t + "' is already registered.");
}
registeredTypeInfoFactories.put(t, factory);
}
// --------------------------------------------------------------------------------------------
// Function specific methods
// --------------------------------------------------------------------------------------------
@PublicEvolving
public static <IN, OUT> TypeInformation<OUT> getMapReturnTypes(
MapFunction<IN, OUT> mapInterface, TypeInformation<IN> inType) {
return getMapReturnTypes(mapInterface, inType, null, false);
}
@PublicEvolving
public static <IN, OUT> TypeInformation<OUT> getMapReturnTypes(
MapFunction<IN, OUT> mapInterface,View on GitHub (pinned to 2f3c205e92)
Solutions
- Consolidate to a single TypeInfoFactory registration per type.
- If different factories are needed for the same type in different contexts, use a single factory that dispatches based on runtime conditions.
- For tests, run each test in a separate JVM or avoid re-registering the same type.
- Check registeredTypeInfoFactories before registering if you suspect a prior registration.
Example fix
// before TypeExtractor.registerFactory(MyType.class, FactoryA.class); // ... later in another module ... TypeExtractor.registerFactory(MyType.class, FactoryB.class); // throws // after // Register only once, in a shared location: TypeExtractor.registerFactory(MyType.class, FactoryA.class);
Defensive patterns
Strategy: validation
Validate before calling
// Check before registering — there is no public getter, so track in your own code
if (alreadyRegisteredTypes.contains(t)) {
throw new IllegalStateException("Factory already registered for " + t);
}
TypeExtractor.registerFactory(t, factory);
alreadyRegisteredTypes.add(t); Try / catch
try {
TypeExtractor.registerFactory(type, factory);
} catch (InvalidTypesException e) {
if (e.getMessage().contains("already registered")) {
// already registered by another module; acceptable
return;
}
throw e;
} Prevention
- Register each type's factory exactly once, ideally in a static initializer of a shared class.
- For tests, use separate JVM forks or avoid re-registering.
- Centralize factory registration in a single bootstrap location.
When it happens
Trigger: Calling TypeExtractor.registerFactory(MyType.class, FactoryA.class) and later TypeExtractor.registerFactory(MyType.class, FactoryB.class). The static map persists for the JVM lifetime, so two separate calls in the same process for the same type trigger this.
Common situations: Multiple modules or libraries each register a TypeInfoFactory for the same type. Static initialization blocks in different classes both registering factories for a shared type. Unit tests that register factories without cleanup and then run in the same JVM.
Related errors
- Class is not a TypeInfoFactory.
- cache file {name}already exists!
- An aggregator is already registered under the given name.
- Could not extract type information.
- TypeInformation '{}' does not supply a mapping of TypeVariab
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/fe45b3ca0c43ce28.
Report an issue: GitHub.