quarkusio/quarkus · error · java.lang.IllegalStateException

Template extension methods that share the namespace <namespa

Error message

Template extension methods that share the namespace <namespace> must be declared on the same class; but declared on <class1> and <class2>

What it means

Thrown when two or more template extension methods declare the same @TemplateExtension namespace but are declared on different classes. Qute requires all extension methods of a given namespace to live on a single class so namespace resolution is unambiguous.

Source

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

        Map<DotName, Map<String, List<TemplateExtensionMethodBuildItem>>> classToNamespaceExtensions = new HashMap<>();
        Map<String, DotName> namespaceToClass = new HashMap<>();

        for (TemplateExtensionMethodBuildItem templateExtension : templateExtensionMethods) {
            String generatedValueResolverClass = existingValueResolvers.getGeneratedClass(templateExtension.getMethod());
            if (generatedValueResolverClass != null) {
                // A ValueResolver of a non-application class was already generated
                generatedValueResolvers.add(generatedValueResolverClass);
                continue;
            }

            if (templateExtension.hasNamespace()) {
                // Group extension methods declared on the same class by namespace
                DotName declaringClassName = templateExtension.getMethod().declaringClass().name();
                DotName namespaceClassName = namespaceToClass.get(templateExtension.getNamespace());
                if (namespaceClassName == null) {
                    namespaceToClass.put(templateExtension.getNamespace(), namespaceClassName);
                } else if (!namespaceClassName.equals(declaringClassName)) {
                    throw new IllegalStateException("Template extension methods that share the namespace "
                            + templateExtension.getNamespace() + " must be declared on the same class; but declared on "
                            + namespaceClassName + " and " + declaringClassName);
                }
                Map<String, List<TemplateExtensionMethodBuildItem>> namespaceToExtensions = classToNamespaceExtensions
                        .get(declaringClassName);
                if (namespaceToExtensions == null) {
                    namespaceToExtensions = new HashMap<>();
                    classToNamespaceExtensions.put(declaringClassName, namespaceToExtensions);
                }
                List<TemplateExtensionMethodBuildItem> namespaceMethods = namespaceToExtensions
                        .get(templateExtension.getNamespace());
                if (namespaceMethods == null) {
                    namespaceMethods = new ArrayList<>();
                    namespaceToExtensions.put(templateExtension.getNamespace(), namespaceMethods);
                }
                namespaceMethods.add(templateExtension);
            } else {
                // Generate ValueResolver per extension method

View on GitHub (pinned to e1c734241f)

Solutions

  1. Move all methods using the same namespace into one class
  2. Change the namespace on one of the colliding classes to a distinct namespace
  3. Remove one of the duplicate extension methods if it is redundant
  4. If it comes from a third-party dependency, exclude/override that dependency or pick a new namespace in your code

Example fix

// before
class A { @TemplateExtension(namespace="money") static String fmt(BigDecimal v){...} }
class B { @TemplateExtension(namespace="money") static String shortFmt(BigDecimal v){...} }

// after
class A { @TemplateExtension(namespace="money")
  static String fmt(BigDecimal v){...}
  static String shortFmt(BigDecimal v){...} }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure each custom namespace is declared on exactly one class
Map<String, Long> nsCount = allExtensionClasses.stream()
    .flatMap(c -> c.namespaces().stream())
    .collect(Collectors.groupingBy(n -> n, Collectors.counting()));
List<String> dupes = nsCount.entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).toList();

Prevention

When it happens

Trigger: Two helper classes both annotated methods with @TemplateExtension(namespace = "cfg") or matching value; a namespace collision introduced after moving one extension method to a shared library class while a local copy remains.

Common situations: Splitting extension methods across utility classes during refactoring; two dependencies each defining extensions in the same custom namespace; copy-pasting an extension class and forgetting to change the namespace.

Related errors


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