{"record":{"id":"4a65c78fc96bddcc","repo":"quarkusio/quarkus","slug":"template-extension-method-declared-on-must-accept","errorCode":null,"errorMessage":"Template extension method declared on  must accept at least one string parameter to match the name: ","messagePattern":"Template extension method declared on  must accept at least one string parameter to match the name: ","errorType":"exception","errorClass":"TemplateException","httpStatus":null,"severity":"error","filePath":"independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java","lineNumber":987,"sourceCode":"                        }\n                    } else {\n                        // No namespace but matches any or regex\n                        params.add(new Param(method.parameterName(i), parameters.get(i), i, ParamKind.BASE));\n                    }\n                } else if (indexed == 1 && !hasNamespace && isNameParameterRequired) {\n                    indexed++;\n                    params.add(new Param(method.parameterName(i), parameters.get(i), i, ParamKind.NAME));\n                } else {\n                    indexed++;\n                    params.add(new Param(method.parameterName(i), parameters.get(i), i, ParamKind.EVAL));\n                }\n            }\n            this.params = params;\n\n            if (isNameParameterRequired) {\n                Param nameParam = getFirst(ParamKind.NAME);\n                if (nameParam == null || !nameParam.type.name().equals(DotNames.STRING)) {\n                    throw new TemplateException(\n                            \"Template extension method declared on \" + method.declaringClass().name()\n                                    + \" must accept at least one string parameter to match the name: \" + method);\n                }\n            }\n            if (!hasNamespace && getFirst(ParamKind.BASE) == null) {\n                throw new TemplateException(\n                        \"Template extension method declared on \" + method.declaringClass().name()\n                                + \" must accept at least one parameter to match the base object: \" + method);\n            }\n\n            for (Param param : params) {\n                if (param.kind == ParamKind.ATTR && !param.type.name().equals(DotNames.OBJECT)) {\n                    throw new TemplateException(\n                            \"Template extension method parameter annotated with @TemplateAttribute declared on \"\n                                    + method.declaringClass().name()\n                                    + \" must be of type java.lang.Object: \" + method);\n                }\n            }","sourceCodeStart":969,"sourceCodeEnd":1005,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java#L969-L1005","documentation":"An extension method that requires a name parameter (@TemplateExtension(matchNames/matchRegex/ANY, or namespace matching by name) must include a java.lang.String parameter that receives the matched name. Qute throws TemplateException in the constructor when isNameParameterRequired is set but no String NAME-kind parameter exists.","triggerScenarios":"Declaring @TemplateExtension(matchRegex=...) or ANY where the name parameter is missing or not java.lang.String (e.g. CharSequence, Object); detected when the ExtensionMethodGenerator is constructed.","commonSituations":"Using CharSequence for the name parameter; removing the name param while keeping matchRegex; copying a fixed-name extension and adding matchNames without adding the parameter.","solutions":["Add a java.lang.String parameter in the position expected for the name","Change an existing name parameter's type to java.lang.String","Remove matchNames/matchRegex/ANY and use a fixed matchName if the name parameter is unwanted"],"exampleFix":"// before\n@TemplateExtension(matchNames = {\"a\", \"b\"})\nstatic String get(Object base) { ... }\n// after\n@TemplateExtension(matchNames = {\"a\", \"b\"})\nstatic String get(Object base, String name) { ... }","handlingStrategy":"validation","validationCode":"if ((ext.matchRegex().isPresent() || ext.matchNames().length > 0 || ext.matchName().equals(TemplateExtension.ANY))\n    && Arrays.stream(m.getParameterTypes()).noneMatch(t -> t == String.class))\n    throw new IllegalStateException(\"Extension must accept a String name parameter: \" + m);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use java.lang.String (not CharSequence) for name parameters","Re-check signatures after changing matching strategy","Write unit tests invoking multi-name extensions"],"tags":["qute","template-extension","signature","build-time"],"backgroundTag":"template-extension-signature-mismatch","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"}