quarkusio/quarkus · error · io.quarkus.qute.TemplateException
Multiple checked templates exist for the template path %s:
Error message
Multiple checked templates exist for the template path %s: - %s - %s
What it means
Each checked template path must map to exactly one @CheckedTemplate class/interface (or template record). collectCheckedTemplates keys checked templates by full path (path + optional '$' + fragmentId); if two distinct classes resolve to the same fullPath the build fails with this TemplateException listing both classes.
Source
Thrown at extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java:460
if (method.isSynthetic() || method.isBridge() || method.parametersCount() != 0) {
continue;
}
reservedNames.add(method.name());
}
for (ClassInfo recordClass : index.getIndex().getAllKnownImplementations(recordInterfaceName)) {
if (!recordClass.isRecord()) {
continue;
}
MethodInfo canonicalConstructor = recordClass.canonicalRecordConstructor();
AnnotationInstance checkedTemplateAnnotation = recordClass.declaredAnnotation(Names.CHECKED_TEMPLATE);
String fragmentId = getCheckedFragmentId(recordClass, checkedTemplateAnnotation);
String templatePath = getCheckedTemplatePath(index.getIndex(), checkedTemplateAnnotation, fragmentId,
recordClass);
String fullPath = templatePath + (fragmentId != null ? "$" + fragmentId : "");
AnnotationTarget checkedTemplate = checkedTemplates.putIfAbsent(fullPath, recordClass);
if (checkedTemplate != null) {
throw new TemplateException(
String.format(
"Multiple checked templates exist for the template path %s:\n\t- %s\n\t- %s",
fullPath, recordClass.name(), checkedTemplate));
}
if (!filePaths.contains(templatePath)
&& isNotLocatedByCustomTemplateLocator(locatorPatternsBuildItem.getLocationPatterns(),
templatePath)) {
List<String> startsWith = new ArrayList<>();
for (String filePath : filePaths.getFilePaths()) {
if (filePath.startsWith(templatePath)
&& filePath.charAt(templatePath.length()) == '.') {
startsWith.add(filePath);
}
}
if (startsWith.isEmpty()) {
throw new TemplateException(
"No template matching the path " + templatePath + " could be found for: "View on GitHub (pinned to e1c734241f)
Solutions
- Find the two classes listed in the message and delete or rename one
- Give one of them an explicit distinct location: @CheckedTemplate(location="items/list2") or basePath=...
- If using records as template records, remove the leftover @CheckedTemplate interface for the same template
- Ensure fragment ids differ when two classes intentionally use the same template file with different fragments
Example fix
// before
// com.a.Templates: @CheckedTemplate(basePath="items") interface Templates { static native TemplateInstance list(); }
// com.b.Templates: @CheckedTemplate(basePath="items") interface Templates { static native TemplateInstance list(); }
// after
// com.a.Templates: basePath="items"
// com.b.Templates: @CheckedTemplate(basePath="orders") interface Templates { static native TemplateInstance list(); } Defensive patterns
Strategy: validation
Validate before calling
// detect duplicate checked template base names before build
Set<String> seen = new HashSet<>();
for (Class<?> c : allCheckedTemplateClasses) {
String path = c.getAnnotation(CheckedTemplate.class) != null
? c.getAnnotation(CheckedTemplate.class).basePath() + "/" + c.getSimpleName()
: c.getName().replace('.', '/');
if (!seen.add(path)) throw new IllegalStateException("Duplicate checked template path: " + path);
} Prevention
- Give each @CheckedTemplate interface a unique basePath or explicit location
- Avoid copying checked-template interfaces between packages unchanged
- Delete obsolete interfaces when converting to template records
- Review the two classes named in the error and keep exactly one per path
When it happens
Trigger: Two @CheckedTemplate interfaces in different packages whose base names produce the same template path (e.g. both default to 'ItemResource/item'); a template record class and an interface both declared for the same template path; duplicate fragment-ids for the same template.
Common situations: Copying an existing checked-template interface into a new package without adjusting @CheckedTemplate(basePath=...); refactoring a class into a record-based template record while leaving the old interface; accidental duplicate nested interfaces with identical names.
Related errors
- Unsupported @CheckedTemplate#defaultName() value: <defaultNa
- Message bundle name [%s] declared on %s must be a valid name
- Message bundle interface name conflict - [%s] is used for bo
- Cannot register [%s] - a localized message bundle interface
- @MessageBundle must be declared on an interface: {bundleClas
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/889ce57f5759cad5.
Report an issue: GitHub.