{"record":{"id":"ce0ad7420c5622e8","repo":"apache/pulsar","slug":"user-class-must-be-concrete-ce0ad7","errorCode":null,"errorMessage":"User class must be concrete","messagePattern":"User class must be concrete","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/windowing/WindowFunctionExecutor.java","lineNumber":148,"sourceCode":"    private TimestampExtractor<T> getTimeStampExtractor(WindowConfig windowConfig) {\n\n        Class<?> theCls;\n        try {\n            theCls = Class.forName(windowConfig.getTimestampExtractorClassName(),\n                    true, Thread.currentThread().getContextClassLoader());\n        } catch (ClassNotFoundException | NoClassDefFoundError cnfe) {\n            throw new RuntimeException(\n                    String.format(\"Timestamp extractor class %s must be in class path\",\n                            windowConfig.getTimestampExtractorClassName()), cnfe);\n        }\n\n        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    }","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/windowing/WindowFunctionExecutor.java#L130-L166","documentation":"getTimeStampExtractor instantiates the configured timestamp extractor reflectively via a no-arg constructor. InstantiationException (or its modern wrapper) is caught and rethrown as \"User class must be concrete\", meaning the extractor class is abstract or an interface and cannot be instantiated. The configured class must be a concrete class with an accessible no-arg constructor.","triggerScenarios":"timestampExtractorClassName points at an abstract base class, interface, or anonymous/abstract generic subclass; reflection calls constructor.newInstance() and gets InstantiationException.","commonSituations":"Pointing config at the TimestampExtractor interface itself; creating an abstract adapter class and forgetting to implement the extract method; lambda or generic anonymous classes whose target type is abstract.","solutions":["Configure a concrete class that implements TimestampExtractor<T> with all methods implemented","If you have an abstract base, create a concrete subclass and reference that in WindowConfig","Ensure the class has a public no-arg constructor","Rebuild and redeploy the function jar"],"exampleFix":"// before\npublic abstract class MyExtractor implements TimestampExtractor<String> { }\n// after\npublic class MyExtractor implements TimestampExtractor<String> {\n    public long extractTimestamp(String record) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(className);\nif (Modifier.isAbstract(c.getModifiers()) || c.isInterface()) {\n    throw new IllegalStateException(\"extractor must be a concrete class: \" + className);\n}","typeGuard":null,"tryCatchPattern":"try {\n    executor.initialize();\n} catch (RuntimeException e) {\n    if (\"User class must be concrete\".equals(e.getMessage())) {\n        throw new IllegalStateException(\"configure a concrete TimestampExtractor subclass\", e);\n    }\n    throw e;\n}","preventionTips":["Never point config at interfaces or abstract adapters","Add a no-arg constructor to every extractor class","Unit-test `new MyExtractor()` before deploying"],"tags":["pulsar-functions","windowing","reflection","abstract-class"],"backgroundTag":"class-instantiation-failed","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"}