{"record":{"id":"7629c7da1cd44c3c","repo":"apache/beam","slug":"subclass-of-class-org-apache-beam-sdk-transforms-combinefn","errorCode":null,"errorMessage":"Subclass of class org.apache.beam.sdk.transforms.CombineFn must be parameterized to be used as a UDAF","messagePattern":"Subclass of class org\\.apache\\.beam\\.sdk\\.transforms\\.CombineFn must be parameterized to be used as a UDAF","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/UdafImpl.java","lineNumber":127,"sourceCode":"    }\n    ParameterizedType parameterizedType = findCombineFnSuperClass();\n    return parameterizedType.getActualTypeArguments()[0];\n  }\n\n  protected Type getOutputType() {\n    return combineFn.getOutputType().getType();\n  }\n\n  private ParameterizedType findCombineFnSuperClass() {\n\n    Class clazz = combineFn.getClass();\n\n    while (!clazz.getSuperclass().equals(CombineFn.class)) {\n      clazz = clazz.getSuperclass();\n    }\n\n    if (!(clazz.getGenericSuperclass() instanceof ParameterizedType)) {\n      throw new IllegalStateException(\n          \"Subclass of \" + CombineFn.class + \" must be parameterized to be used as a UDAF\");\n    }\n    return (ParameterizedType) clazz.getGenericSuperclass();\n  }\n}\n","sourceCodeStart":109,"sourceCodeEnd":133,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/UdafImpl.java#L109-L133","documentation":"Beam SQL walks the UDAF's class hierarchy up to CombineFn and requires that the direct CombineFn superclass be a parameterized type, because the type parameters (InputT, AccumT, OutputT) are how SQL types are inferred. A subclass that extends CombineFn raw (or via a non-parameterized chain) gives no type information at runtime due to erasure, so the UDAF cannot be built.","triggerScenarios":"Registering a UDAF whose class hierarchy reaches CombineFn through a raw (non-generic) extends clause, e.g. class MyFn extends CombineFn, or an intermediate generic subclass instantiated without type arguments.","commonSituations":"Migrating legacy CombineFns written with raw types; defining CombineFn subclasses inside generic classes where the extends clause loses parameterization; copy-pasting a CombineFn but dropping the <...> type arguments.","solutions":["Parameterize the CombineFn subclass explicitly: class MySumFn extends CombineFn<Long, long[], Long> instead of raw extends CombineFn","Ensure every class in the hierarchy between your UDAF and CombineFn propagates concrete type parameters","Verify with clazz.getGenericSuperclass() instanceof ParameterizedType before registering"],"exampleFix":"// before\nclass MySumFn extends CombineFn { ... }\n// after\nclass MySumFn extends CombineFn<Long, long[], Long> { ... }","handlingStrategy":"validation","validationCode":"Class<?> c = myFn.getClass();\nwhile (c != null && !c.getSuperclass().equals(CombineFn.class)) c = c.getSuperclass();\nboolean ok = c != null && c.getGenericSuperclass() instanceof ParameterizedType;","typeGuard":"static boolean isParameterizedCombineFn(Class<?> clazz) {\n  while (clazz != null && !clazz.getSuperclass().equals(CombineFn.class)) clazz = clazz.getSuperclass();\n  return clazz != null && clazz.getGenericSuperclass() instanceof ParameterizedType;\n}","tryCatchPattern":"try {\n  sqlEnv.registerUdaf(name, myFn);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"must be parameterized\")) {\n    throw new IllegalStateException(\"Add <InputT, AccumT, OutputT> to 'extends CombineFn<...>' in \" + myFn.getClass().getName(), e);\n  } else throw e;\n}","preventionTips":["Never extend CombineFn as a raw type; always supply <InputT, AccumT, OutputT>","Keep intermediate subclasses generic-pass-through with concrete parameters","Add a reflection-based registration test that checks getGenericSuperclass() instanceof ParameterizedType"],"tags":["java","beam-sql","generics","udaf","raw-types"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}