quarkusio/quarkus · error · IllegalStateException

No template variant found

Error message

No template variant found

What it means

MailTemplateInstanceImpl.send() renders a Qute template and mails the result. When the underlying Qute TemplateInstance exposes no TemplateInstance.VARIANTS attribute, send() cannot know which variants (text/html, text/plain) to render, so it throws this IllegalStateException. This happens when the injected MailTemplate does not come from a Qute template with multiple declared variants.

Source

Thrown at extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateInstanceImpl.java:159

                                                    .setAttribute(TemplateInstance.SELECTED_VARIANT, variant).renderAsync();
                                        }
                                    })));
                }
            }
            if (results.isEmpty()) {
                throw new IllegalStateException("No suitable template variant found");
            }
            List<Uni<String>> unis = results.stream().map(Result::resolve).collect(Collectors.toList());
            return Uni.combine().all().unis(unis)
                    .combinedWith(combine(results))
                    .chain(new Function<Mail, Uni<? extends Void>>() {
                        @Override
                        public Uni<? extends Void> apply(Mail m) {
                            return mailer.send(m);
                        }
                    });
        } else {
            throw new IllegalStateException("No template variant found");
        }
    }

    private Function<List<?>, Mail> combine(List<Result> results) {
        return new Function<List<?>, Mail>() {
            @Override
            public Mail apply(List<?> resolved) {
                for (int i = 0; i < resolved.size(); i++) {
                    Result result = results.get(i);
                    // We can safely cast, as we know that the results are Strings.
                    String content = (String) resolved.get(i);
                    if (result.variant.getContentType().equals(Variant.TEXT_HTML)) {
                        mail.setHtml(content);
                    } else if (result.variant.getContentType().equals(Variant.TEXT_PLAIN)) {
                        mail.setText(content);
                    }
                }
                return mail;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Ensure the template directory contains variant files with proper suffixes, e.g. templates/welcome.qute.html and templates/welcome.qute.txt, matching the @Location value.
  2. If building a TemplateInstance programmatically, set instance.setAttribute(TemplateInstance.VARIANTS, List.of(variant...)) before calling send().
  3. If you only need a fixed body, skip the mail template and use ReactiveMailer directly: mailer.send(Mail.withText(to, subject, body)).
  4. Verify @Location("...") path matches the actual resource under src/main/resources/templates.

Example fix

// before (single non-variant template)
@Inject @Location("welcome") MailTemplate welcome; // templates/welcome.qute only
welcome.to(to).subject(sub).send();

// after (variant files)
// src/main/resources/templates/welcome.qute.html
// src/main/resources/templates/welcome.qute.txt
welcome.to(to).subject(sub).send();
Defensive patterns

Strategy: validation

Validate before calling

Object variants = templateInstance.templateInstance().getAttribute(TemplateInstance.VARIANTS);
if (variants == null) {
    throw new IllegalStateException("Template has no variants; add .qute.html/.qute.txt files or set the VARIANTS attribute");
}

Try / catch

try {
    template.send().await().indefinitely();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("No template variant")) {
        LOG.error("Mail template lacks text/html or text/plain variants", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling send() on a MailTemplateInstance whose Qute template was not loaded with template variants (e.g. the template defines no .qute.html/.qute.txt variant files, or the TemplateInstance was created programmatically without setting the VARIANTS attribute).

Common situations: Injecting a MailTemplate via @Location pointing to a plain template that only has a single non-variant file; using a custom TemplateInstance built by hand (e.g. via MailTemplateInstanceAdaptor) without variants; renaming template files so the html/txt variant suffixes no longer match.

Related errors


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