{"record":{"id":"c182b6e54c4e3795","repo":"quarkusio/quarkus","slug":"template-extension-method-declared-on-must-not-re","errorCode":null,"errorMessage":"Template extension method declared on  must not return void: ","messagePattern":"Template extension method declared on  must not return void: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java","lineNumber":85,"sourceCode":"\n    public static final String MATCH_NAME = \"matchName\";\n    public static final String MATCH_NAMES = \"matchNames\";\n    public static final String MATCH_REGEX = \"matchRegex\";\n    public static final String PRIORITY = \"priority\";\n    public static final String NAMESPACE = \"namespace\";\n    public static final String PATTERN = \"pattern\";\n\n    public ExtensionMethodGenerator(IndexView index, ClassOutput classOutput) {\n        super(index, classOutput);\n    }\n\n    public static void validate(MethodInfo method, String namespace) {\n        if (!Modifier.isStatic(method.flags())) {\n            throw new IllegalStateException(\n                    \"Template extension method declared on \" + method.declaringClass().name() + \"  must be static: \" + method);\n        }\n        if (method.returnType().kind() == Kind.VOID) {\n            throw new IllegalStateException(\"Template extension method declared on \" + method.declaringClass().name()\n                    + \" must not return void: \" + method);\n        }\n        if (Modifier.isPrivate(method.flags())) {\n            throw new IllegalStateException(\"Template extension method declared on \" + method.declaringClass().name()\n                    + \" must not be private: \" + method);\n        }\n    }\n\n    /**\n     *\n     * @param method\n     * @param matchName\n     * @param matchNames\n     * @param matchRegex\n     * @param priority\n     * @return the fully qualified name of the generated class\n     */\n    public String generate(MethodInfo method, String matchName, List<String> matchNames, String matchRegex, Integer priority) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java#L67-L103","documentation":"Qute's template extension methods are invoked reflectively/bytecode-generated at build time, so they must return a value usable in an expression. This IllegalStateException is thrown during validation when a method annotated with @TemplateExtension (or in a namespace class) has a void return type, which cannot appear as a value in a template expression.","triggerScenarios":"Annotating a static method with @TemplateExtension (or registering it as a namespace extension) where the method's return type is void, e.g. 'void format(String s)'. Detected by ExtensionMethodGenerator.validate during template class generation.","commonSituations":"Porting utility methods that were mutation-style (returning void) into template extensions; refactoring a method to void after adding the annotation; mistakenly annotating setters or collection mutators.","solutions":["Change the extension method to return a value (the value used in the template expression)","Remove the @TemplateExtension annotation if the method is not meant to be callable from templates","Split the logic: keep a void method and add a static wrapper returning the computed result"],"exampleFix":"// before\n@TemplateExtension\nstatic void format(BigDecimal val) { System.out.println(val); }\n// after\n@TemplateExtension\nstatic String format(BigDecimal val) { return val.toPlainString(); }","handlingStrategy":"validation","validationCode":"// Build-time check before registering:\nif (java.lang.reflect.Modifier.isStatic(m.getModifiers()) && m.getReturnType() == void.class)\n    throw new IllegalStateException(\"@TemplateExtension method must not return void: \" + m);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never annotate void methods with @TemplateExtension","Review extension method signatures in code review","Add an ArchUnit/custom test asserting extension methods return non-void"],"tags":["qute","template-extension","build-time","validation"],"backgroundTag":"void-return-template-extension","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}