apache/flink · error · InvalidTypesException
SQL time type '{}' expected but was '{}'.
Error message
SQL time type '{}' expected but was '{}'. What it means
Thrown during input type validation when the TypeInformation is SqlTimeTypeInfo but the reflected Type resolves to a different SQL time type than expected. For example, the stream carries Timestamp but the function expects Time. The `typeInfo.equals(actual)` check fails, producing this error with both type names.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:1525
// check if correct basic type
if (!typeInfo.equals(actual)) {
throw new InvalidTypesException(
"Basic type '" + typeInfo + "' expected but was '" + actual + "'.");
}
}
// check for Java SQL time types
else if (typeInfo instanceof SqlTimeTypeInfo) {
TypeInformation<?> actual;
// check if SQL time type at all
if (!(type instanceof Class<?>)
|| (actual = SqlTimeTypeInfo.getInfoFor((Class<?>) type)) == null) {
throw new InvalidTypesException("SQL time type expected.");
}
// check if correct SQL time type
if (!typeInfo.equals(actual)) {
throw new InvalidTypesException(
"SQL time type '" + typeInfo + "' expected but was '" + actual + "'.");
}
}
// check for Java Tuples
else if (typeInfo instanceof TupleTypeInfo) {
// check if tuple at all
if (!(isClassType(type) && Tuple.class.isAssignableFrom(typeToClass(type)))) {
throw new InvalidTypesException("Tuple type expected.");
}
// do not allow usage of Tuple as type
if (isClassType(type) && typeToClass(type).equals(Tuple.class)) {
throw new InvalidTypesException("Concrete subclass of Tuple expected.");
}
// go up the hierarchy until we reach immediate child of Tuple (with or without
// generics)View on GitHub (pinned to 2f3c205e92)
Solutions
- Align the function's temporal type parameter with the DataStream's element type
- Add a conversion step to transform between SQL temporal types
- Standardize on one SQL temporal type throughout the pipeline
Example fix
// before — Timestamp vs Date mismatch
DataStream<java.sql.Date> stream = ...;
stream.map(new MapFunction<java.sql.Timestamp, X>() { ... });
// after — align types
stream.map(date -> new java.sql.Timestamp(date.getTime()))
.map(new MapFunction<java.sql.Timestamp, X>() { ... }); Defensive patterns
Strategy: validation
Validate before calling
// Verify SQL time types match
TypeInformation<?> streamType = stream.getType();
if (streamType instanceof SqlTimeTypeInfo) {
SqlTimeTypeInfo<?> sqlType = (SqlTimeTypeInfo<?>) streamType;
// Ensure function input matches
Class<?> funcInputClass = java.sql.Timestamp.class; // from function signature
if (!sqlType.getTypeClass().equals(funcInputClass)) {
throw new IllegalStateException(
"SQL time mismatch: stream has " + sqlType.getTypeClass()
+ " but function expects " + funcInputClass);
}
} Prevention
- Standardize on one SQL temporal type throughout the pipeline
- Add explicit conversion steps between Date, Time, and Timestamp when needed
- Document the expected temporal type in function JavaDoc
- Use unit tests to verify temporal type compatibility between operators
When it happens
Trigger: A function declares `MapFunction<java.sql.Timestamp, X>` but the DataStream carries `java.sql.Date` or `java.sql.Time`. Both are SqlTimeTypeInfo, but they are different SQL temporal types. The equality check fails.
Common situations: Swapping Date/Time/Timestamp types in a pipeline refactor. Connecting a JDBC source emitting Timestamp to a function expecting Time. Inconsistent temporal type usage across operators.
Related errors
- SQL time type expected.
- Basic type expected.
- Basic type '{}' expected but was '{}'.
- Tuple type expected.
- Concrete subclass of Tuple expected.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/7c8fc9b5f3a20ef7.
Report an issue: GitHub.