{"record":{"id":"5b6b028937c4d81b","repo":"apache/flink","slug":"the-return-type-of-function-functionname-could","errorCode":null,"errorMessage":"The return type of function '{functionName}' could not be determined automatically, due to type erasure. You can give type information hints by using the returns(...) method on the result of the transformation call, or by letting your function implement the 'ResultTypeQueryable' interface.","messagePattern":"The return type of function '(.+?)' could not be determined automatically, due to type erasure\\. You can give type information hints by using the returns\\(\\.\\.\\.\\) method on the result of the transformation call, or by letting your function implement the 'ResultTypeQueryable' interface\\.","errorType":"exception","errorClass":"InvalidTypesException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/dag/Transformation.java","lineNumber":581,"sourceCode":"            throw new IllegalStateException(\n                    \"TypeInformation cannot be filled in for the type after it has been used. \"\n                            + \"Please make sure that the type info hints are the first call after\"\n                            + \" the transformation function, \"\n                            + \"before any access to types or semantic properties, etc.\");\n        }\n        this.outputType = outputType;\n    }\n\n    /**\n     * Returns the output type of this {@code Transformation} as a {@link TypeInformation}. Once\n     * this is used once the output type cannot be changed anymore using {@link #setOutputType}.\n     *\n     * @return The output type of this {@code Transformation}\n     */\n    public TypeInformation<T> getOutputType() {\n        if (outputType instanceof MissingTypeInfo) {\n            MissingTypeInfo typeInfo = (MissingTypeInfo) this.outputType;\n            throw new InvalidTypesException(\n                    \"The return type of function '\"\n                            + typeInfo.getFunctionName()\n                            + \"' could not be determined automatically, due to type erasure. \"\n                            + \"You can give type information hints by using the returns(...) \"\n                            + \"method on the result of the transformation call, or by letting \"\n                            + \"your function implement the 'ResultTypeQueryable' \"\n                            + \"interface.\",\n                    typeInfo.getTypeException());\n        }\n        typeUsed = true;\n        return this.outputType;\n    }\n\n    /**\n     * Set the buffer timeout of this {@code Transformation}. The timeout defines how long data may\n     * linger in a partially full buffer before being sent over the network.\n     *\n     * <p>Lower timeouts lead to lower tail latencies, but may affect throughput. For Flink 1.5+,","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/dag/Transformation.java#L563-L599","documentation":"When Flink cannot infer a transformation's return type (typically due to generic type erasure), it stores a MissingTypeInfo placeholder. On the first getOutputType() call it throws InvalidTypesException telling the user the type could not be determined and to supply a hint, surfacing the problem at job-construction time rather than at runtime.","triggerScenarios":"Calling getOutputType() (or any operation needing the output type) on a transformation whose function returns a generic type Flink could not resolve — e.g., a lambda or anonymous MapFunction returning List<X> or a parameterized POJO whose type argument is erased.","commonSituations":"Lambdas or anonymous functions returning generic collections/POJOs where the type parameter is erased; Tuple returns without explicit TupleTypeInfo; nested generics; using .map(x -> new Result(...)) for a non-final Result class whose generic signature is invisible.","solutions":["Add .returns(TypeInformation.of(...)) as the first call after the transformation function.","Implement ResultTypeQueryable on your function and return the TypeInformation explicitly.","Replace the lambda with a named class so Flink can introspect the generic method signature.","Use Types.POJO(...) / Types.TUPLE(...) hints to make the return type concrete."],"exampleFix":"// before: data.map(x -> new MyResult(...))  // type erased -> MissingTypeInfo -> throws on getOutputType\n// after:  data.map(x -> new MyResult(...)).returns(TypeInformation.of(MyResult.class))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    TypeInformation<T> out = transform.getOutputType();\n} catch (InvalidTypesException e) {\n    if (e.getMessage().contains(\"could not be determined automatically\")) {\n        // Add .returns(...) after the transformation or implement ResultTypeQueryable\n        log.error(\"Return type erased; supply a type hint or implement ResultTypeQueryable\");\n    }\n    throw e;\n}","preventionTips":["Add .returns(TypeInformation.of(...)) right after any transformation returning a generic type.","Implement ResultTypeQueryable on functions returning generics to make the type explicit.","Use named classes instead of lambdas so Flink can read the generic signature.","Run the job graph construction in a unit test to surface type-erasure failures early."],"tags":["type-information","type-erasure","datastream-api"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}