quarkusio/quarkus · error · RuntimeException

Invalid template link [${templateLink}] - Expeting a link th

Error message

Invalid template link [${templateLink}] - Expeting a link that ends with .html

What it means

QuteDataPageBuilder.templateLink(String) validates that the Qute template link is a non-empty path ending in '.html' because the Dev UI resolves and serves the underlying Qute template file by that path. Anything else cannot be located or rendered.

Source

Thrown at extensions/devui/deployment-spi/src/main/java/io/quarkus/devui/spi/page/QuteDataPageBuilder.java:17

package io.quarkus.devui.spi.page;

public class QuteDataPageBuilder extends PageBuilder<QuteDataPageBuilder> {
    private static final String DOT_HTML = ".html";
    private static final String QWC_DATA_QUTE_PAGE_JS = "qwc-data-qute-page.js";
    private String templateLink;

    protected QuteDataPageBuilder(String title) {
        super();
        super.title = title;
        super.internalComponent = true;// As external page runs on "internal" namespace
        super.componentLink = QWC_DATA_QUTE_PAGE_JS;
    }

    public QuteDataPageBuilder templateLink(String templateLink) {
        if (templateLink == null || templateLink.isEmpty() || !templateLink.endsWith(DOT_HTML)) {
            throw new RuntimeException(
                    "Invalid template link [" + templateLink + "] - Expeting a link that ends with .html");
        }

        this.templateLink = templateLink;
        return this;
    }

    @Override
    public Page build() {

        super.metadata("templatePath", getTemplatePath());
        return super.build();
    }

    public String getTemplatePath() {
        return "/dev-ui/" + this.templateLink;
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Append the extension: templateLink("templates/my-page.html")
  2. Reference templates that exist under META-INF/resources of the extension and end with .html
  3. Normalize the input: if (link != null && !link.endsWith(".html")) link = link + ".html"; before calling
  4. Verify the file is present in the built artifact (check target/classes / the extension jar)

Example fix

// before
quteDataPageBuilder().templateLink("templates/status"); // throws
// after
quteDataPageBuilder().templateLink("templates/status.html");
Defensive patterns

Strategy: validation

Validate before calling

if (link == null || link.isBlank() || !link.endsWith(".html")) {
    throw new IllegalStateException("templateLink must be a non-empty path ending in .html: " + link);
}

Type guard

boolean isValidTemplateLink(String l) {
    return l != null && !l.isBlank() && l.toLowerCase().endsWith(".html");
}

Try / catch

try {
    quteDataPageBuilder().templateLink(link);
} catch (RuntimeException e) {
    if (e.getMessage().contains("Expeting a link that ends with .html")) {
        quteDataPageBuilder().templateLink(link + ".html");
    } else throw e;
}

Prevention

When it happens

Trigger: Calling quteDataPageBuilder().templateLink("templates/foo") or templateLink("") / templateLink(null) — i.e. missing the .html extension or passing an empty value.

Common situations: Storing the template path in config without the extension; users pointing at Markdown/asciidoc source files instead of the compiled HTML; path built by string concatenation dropping the suffix; classpath resource actually missing so the suffix was 'fixed' by removing it.

Related errors


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