quarkusio/quarkus · error

Template extension method declared on must be static:

Error message

Template extension method declared on  must be static: 

What it means

Qute template extension methods (value resolvers exposed via @TemplateExtension or namespace extension methods) must be static. ExtensionMethodGenerator.validate() throws IllegalStateException during build-time bytecode generation when the annotated method is an instance method, since Qute calls the method statically without a receiver instance.

Source

Thrown at independent-projects/qute/generator/src/main/java/io/quarkus/qute/generator/ExtensionMethodGenerator.java:81

    public static final DotName TEMPLATE_EXTENSION = DotName.createSimple(TemplateExtension.class.getName());
    public static final DotName TEMPLATE_ATTRIBUTE = DotName.createSimple(TemplateExtension.TemplateAttribute.class.getName());
    public static final String SUFFIX = "_Extension" + ValueResolverGenerator.SUFFIX;
    public static final String NAMESPACE_SUFFIX = "_Namespace" + SUFFIX;

    public static final String MATCH_NAME = "matchName";
    public static final String MATCH_NAMES = "matchNames";
    public static final String MATCH_REGEX = "matchRegex";
    public static final String PRIORITY = "priority";
    public static final String NAMESPACE = "namespace";
    public static final String PATTERN = "pattern";

    public ExtensionMethodGenerator(IndexView index, ClassOutput classOutput) {
        super(index, classOutput);
    }

    public static void validate(MethodInfo method, String namespace) {
        if (!Modifier.isStatic(method.flags())) {
            throw new IllegalStateException(
                    "Template extension method declared on " + method.declaringClass().name() + "  must be static: " + method);
        }
        if (method.returnType().kind() == Kind.VOID) {
            throw new IllegalStateException("Template extension method declared on " + method.declaringClass().name()
                    + " must not return void: " + method);
        }
        if (Modifier.isPrivate(method.flags())) {
            throw new IllegalStateException("Template extension method declared on " + method.declaringClass().name()
                    + " must not be private: " + method);
        }
    }

    /**
     *
     * @param method
     * @param matchName
     * @param matchNames
     * @param matchRegex

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add the static modifier to the extension method.
  2. If the method needs instance state, make it static and pass required values as parameters, or use a different resolver approach (e.g. a ValueResolver/template data).
  3. Ensure the class containing the method is indexed (not needed for static fix, but the class must be part of the app).
  4. Rebuild with ./mvnw install after the change; the error occurs during augmentation.

Example fix

// before
@TemplateExtension
String shout(String s) { return s.toUpperCase() + "!"; }
// after
@TemplateExtension
static String shout(String s) { return s.toUpperCase() + "!"; }
Defensive patterns

Strategy: validation

Validate before calling

// check before build
for (MethodInfo m : extensionMethods) {
    if (!Modifier.isStatic(m.flags())) {
        throw new IllegalStateException("@TemplateExtension method must be static: " + m);
    }
}

Try / catch

try {
    quarkusBuild augmentation...
} catch (IllegalStateException e) {
    if (e.getMessage().contains("must be static")) {
        // add 'static' to the annotated extension method
    }
}

Prevention

When it happens

Trigger: Declaring a template extension method as non-static — e.g. @TemplateExtension on an instance method of a CDI bean or helper class — then running Quarkus augmentation; building templates with a namespace method that isn't static.

Common situations: Migrating an older extension style to @TemplateExtension and forgetting 'static'; adding @TemplateExtension to a regular bean method; copying an example but dropping the static modifier.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/eff9f6e9334029aa. Report an issue: GitHub.