quarkusio/quarkus · error · java.lang.IllegalStateException

No template extension methods declared on <class>; a templat

Error message

No template extension methods declared on <class>; a template extension method must be static, non-private and must not return void

What it means

Thrown when a class is annotated with @TemplateExtension (on the class, no specific methods listed) but Qute finds no valid template extension methods inside it. A valid extension method must be static, non-private, and must not return void.

Source

Thrown at extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java:1849

                    // Filter out non-static, synthetic, private and void methods
                    continue;
                }
                if ((namespace == null || namespace.isEmpty()) && method.parameterTypes().isEmpty()) {
                    // Filter out methods with no params for non-namespace extensions
                    continue;
                }
                if (methods.containsKey(method)) {
                    // Skip methods annotated with @TemplateExtension - method-level annotation takes precedence
                    skippedMethodLevelAnnotation = true;
                    continue;
                }
                found.add(method);
                LOGGER.debugf("Found template extension method %s declared on %s", method,
                        method.declaringClass().name());
            }

            if (found.isEmpty() && !skippedMethodLevelAnnotation) {
                throw new IllegalStateException("No template extension methods declared on " + entry.getKey()
                        + "; a template extension method must be static, non-private and must not return void");
            }
            for (MethodInfo method : found) {
                produceExtensionMethod(index, extensionMethods, method, entry.getValue());
            }
        }
    }

    private void produceExtensionMethod(IndexView index, BuildProducer<TemplateExtensionMethodBuildItem> extensionMethods,
            MethodInfo method, AnnotationInstance extensionAnnotation) {
        // Analyze matchName and priority so that it could be used during validation
        byte matchers = 0;
        String matchName = null;
        AnnotationValue matchNameValue = extensionAnnotation.value(ExtensionMethodGenerator.MATCH_NAME);
        if (matchNameValue != null) {
            matchName = matchNameValue.asString();
            matchers++;
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Make the extension method static and at least package-private (prefer public), with a non-void return type
  2. Add the first parameter as the extended type, e.g. public static String shout(String self)
  3. If the class should host no extensions, remove the @TemplateExtension annotation
  4. Use @TemplateExtension on individual methods if class-level discovery does not fit

Example fix

// before
@TemplateExtension
public class StringExt {
    private void trimAll(String s) { } // private + void
}

// after
@TemplateExtension
public class StringExt {
    public static String trimAll(String self) {
        return self.strip();
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate an extension class before annotating it with @TemplateExtension
boolean valid = Modifier.isStatic(m.getModifiers())
    && !Modifier.isPrivate(m.getModifiers())
    && m.getReturnType() != void.class;

Prevention

When it happens

Trigger: Annotating a class with @TemplateExtension but its only candidate methods are instance (non-static) methods, private methods, or void-returning methods; the matchName/value/condition attributes on @TemplateExtension on individual methods disqualify all methods so `found` stays empty while no method-level annotation was seen (skippedMethodLevelAnnotation false).

Common situations: Copying an extension helper class into a CDI-aware project where methods became instance methods; accidentally marking the extension method private; writing a void mutating method expecting it to work as an extension.

Related errors


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