{"record":{"id":"fca9b01dc8be0e55","repo":"apache/beam","slug":"cannot-get-type-arguments-for-s-must-implement-parameterized","errorCode":null,"errorMessage":"Cannot get type arguments for %s: must implement parameterized %s","messagePattern":"Cannot get type arguments for (.+?): must implement parameterized (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/LazyAggregateCombineFn.java","lineNumber":152,"sourceCode":"    public LazyUdafImpl(LazyAggregateCombineFn lazyFn) {\n      super(lazyFn);\n      this.lazyFn = lazyFn;\n    }\n\n    private Type[] getTypeArguments() {\n      Class clazz = lazyFn.getAggregateFn().getClass();\n      while (clazz != null) {\n        for (Type genericInterface : clazz.getGenericInterfaces()) {\n          if (genericInterface instanceof ParameterizedType) {\n            ParameterizedType parameterizedType = ((ParameterizedType) genericInterface);\n            if (parameterizedType.getRawType().equals(AggregateFn.class)) {\n              return parameterizedType.getActualTypeArguments();\n            }\n          }\n        }\n        clazz = clazz.getSuperclass();\n      }\n      throw new IllegalStateException(\n          String.format(\n              \"Cannot get type arguments for %s: must implement parameterized %s\",\n              lazyFn, AggregateFn.class.getSimpleName()));\n    }\n\n    @Override\n    protected Type getInputType() {\n      return getTypeArguments()[0];\n    }\n\n    @Override\n    protected Type getOutputType() {\n      return getTypeArguments()[2];\n    }\n  }\n}\n","sourceCodeStart":134,"sourceCodeEnd":169,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/LazyAggregateCombineFn.java#L134-L169","documentation":"LazyAggregateCombineFn.getTypeArguments walks the class hierarchy of a user's AggregateFn to find the parameterized AggregateFn<A, O> supertype and read its type arguments, deferring expensive reflection until needed. If the whole hierarchy is exhausted without a parameterized AggregateFn supertype (raw or non-generic subclass), it cannot infer input/output types and throws IllegalStateException.","triggerScenarios":"Registering an aggregate function whose class (or any superclass up to Object) does not directly extend AggregateFn<InputT, OutputT> with concrete type parameters — e.g. a raw subclass 'class MyAgg extends AggregateFn' or one extending a non-parameterized intermediate class.","commonSituations":"Using raw types to suppress generics warnings; inheriting via an intermediate class that was itself declared raw; migrating legacy UDAFs to the AggregateFn API without adding type parameters.","solutions":["Declare your aggregate class with concrete type arguments: class MySum extends AggregateFn<Long, Long> { ... }.","If using an intermediate base class, parameterize it too (class Base extends AggregateFn<Long, Long>; class MySum extends Base).","Remove raw-type usage flagged by the compiler's unchecked warnings on your AggregateFn subclasses.","Alternatively implement BeamTypeFactory/InferredJavaType style explicit type supply if your Beam version allows."],"exampleFix":"// before\nclass MySum extends AggregateFn { ... } // raw type\n// after\nclass MySum extends AggregateFn<Long, Long> { ... }","handlingStrategy":"validation","validationCode":"static <I,O> boolean hasParameterizedAggregateFn(Class<?> c) {\n  for (Class<?> k = c; k != null; k = k.getSuperclass()) {\n    for (java.lang.reflect.Type t : k.getGenericSuperclass() instanceof Class\n        ? new java.lang.reflect.Type[0]\n        : new java.lang.reflect.Type[]{k.getGenericSuperclass()}) {\n      if (t instanceof java.lang.reflect.ParameterizedType\n          && ((java.lang.reflect.ParameterizedType) t).getRawType() == AggregateFn.class) return true;\n    }\n  }\n  return false;\n}","typeGuard":"static boolean isTypedAggregateFn(Object fn) {\n  return java.lang.reflect.Array.get(fn.getClass().getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType ? fn.getClass() : Object.class, 0) != null\n      || fn.getClass().getGenericSuperclass() instanceof java.lang.reflect.ParameterizedType;\n}","tryCatchPattern":"try {\n  pipeline.apply(SqlTransform.query(...));\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"Cannot get type arguments\")) {\n    throw new IllegalArgumentException(\"AggregateFn subclass must extend AggregateFn<InputT, OutputT> with concrete types\", e);\n  }\n  throw e;\n}","preventionTips":["Never declare AggregateFn subclasses as raw types; enable -Xlint:rawtypes and treat warnings as errors.","Parameterize every intermediate base class between your UDAF and AggregateFn.","Unit-test registering each aggregate function before running pipelines."],"tags":["java","generics","reflection","udaf","beam-sql"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}