{"record":{"id":"bddcd56871be5d4e","repo":"apache/pulsar","slug":"inconsistent-types-found-between-function-input-ty","errorCode":null,"errorMessage":"Inconsistent types found between function input type and timestamp extractor type:  function type = ${typeArgs0}, timestamp extractor type = ${timestampExtractorTypeArgs0}","messagePattern":"Inconsistent types found between function input type and timestamp extractor type:  function type = (.+?), timestamp extractor type = (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/windowing/WindowFunctionExecutor.java","lineNumber":160,"sourceCode":"        Object result;\n        try {\n            Constructor<?> constructor = theCls.getDeclaredConstructor();\n            constructor.setAccessible(true);\n            result = constructor.newInstance();\n        } catch (InstantiationException ie) {\n            throw new RuntimeException(\"User class must be concrete\", ie);\n        } catch (NoSuchMethodException e) {\n            throw new RuntimeException(\"User class doesn't have such method\", e);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(\"User class must have a no-arg constructor\", e);\n        } catch (InvocationTargetException e) {\n            throw new RuntimeException(\"User class constructor throws exception\", e);\n        }\n        Class<?>[] timestampExtractorTypeArgs = TypeResolver.resolveRawArguments(\n                TimestampExtractor.class, result.getClass());\n        Class<?>[] typeArgs = TypeResolver.resolveRawArguments(Function.class, this.getClass());\n        if (!typeArgs[0].equals(timestampExtractorTypeArgs[0])) {\n            throw new RuntimeException(\n                    \"Inconsistent types found between function input type and timestamp extractor type: \"\n                            + \" function type = \" + typeArgs[0] + \", timestamp extractor type = \"\n                            + timestampExtractorTypeArgs[0]);\n        }\n        return (TimestampExtractor<T>) result;\n    }\n\n    private TriggerPolicy<Record<T>, ?> getTriggerPolicy(WindowConfig windowConfig, WindowManager<Record<T>> manager,\n                                                         EvictionPolicy<Record<T>, ?> evictionPolicy, Context context) {\n        if (windowConfig.getSlidingIntervalCount() != null) {\n            if (this.isEventTime()) {\n                return new WatermarkCountTriggerPolicy<>(\n                        windowConfig.getSlidingIntervalCount(), manager, evictionPolicy, manager);\n            } else {\n                return new CountTriggerPolicy<>(windowConfig.getSlidingIntervalCount(), manager, evictionPolicy);\n            }\n        } else {\n            if (this.isEventTime()) {","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/windowing/WindowFunctionExecutor.java#L142-L178","documentation":"WindowFunctionExecutor.getTimeStampExtractor validates that the generic input type of the user's Function class (typeArgs[0]) matches the generic type of the user-provided TimestampExtractor. Apache Pulsar throws this RuntimeException at window setup when TypeResolver resolves the raw generic arguments and the two classes differ, because events would otherwise be fed to the extractor with the wrong type.","triggerScenarios":"Registering a TimestampExtractor whose generic parameter does not equal the Function's input generic, e.g. Function<String, ...> paired with TimestampExtractor<Long>, or leaving the extractor's type parameter untyped so resolution yields Object or a raw type.","commonSituations":"Copy-pasting a sample TimestampExtractor into a function with a different input POJO; refactoring the function input type without updating the extractor; using a raw (non-generic) extractor class that resolves to the wrong raw argument.","solutions":["Make the TimestampExtractor's generic parameter exactly match the Function's input type parameter.","Check the resolved classes by logging typeArgs[0] and timestampExtractorTypeArgs[0] and aligning the generics.","If a raw type was intended, parameterize both classes explicitly instead of relying on raw types."],"exampleFix":"// before\npublic class MyFunction implements Function<String, Void> { ... }\npublic class MyExtractor implements TimestampExtractor<Long> { ... }\n// after\npublic class MyFunction implements Function<String, Void> { ... }\npublic class MyExtractor implements TimestampExtractor<String> { ... }","handlingStrategy":"validation","validationCode":"Class<?>[] typeArgs = TypeResolver.resolveRawArguments(Function.class, fnClass);\nClass<?>[] teArgs = TypeResolver.resolveRawArguments(TimestampExtractor.class, extractorClass);\nif (!typeArgs[0].equals(teArgs[0])) {\n    throw new IllegalStateException(\"Function input \" + typeArgs[0] + \" != extractor type \" + teArgs[0]);\n}","typeGuard":"static <F, E> boolean typesMatch(Class<? extends Function<F, ?>> fn, Class<? extends TimestampExtractor<E>> te) {\n    return TypeResolver.resolveRawArguments(Function.class, fn)[0]\n        .equals(TypeResolver.resolveRawArguments(TimestampExtractor.class, te)[0]);\n}","tryCatchPattern":null,"preventionTips":["Always parameterize Function and TimestampExtractor with the same concrete type.","Unit-test window setup early to surface generic mismatches at deploy time.","Avoid raw types; enable -Xlint:rawtypes."],"tags":["java","generics","pulsar-functions","windowing"],"backgroundTag":"generic-type-mismatch","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}