{"record":{"id":"e4bd61ace7c5a48a","repo":"quarkusio/quarkus","slug":"invalid-template-link-templatelink-expeting","errorCode":null,"errorMessage":"Invalid template link [${templateLink}] - Expeting a link that ends with .html","messagePattern":"Invalid template link \\[(.+?)\\] - Expeting a link that ends with \\.html","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/devui/deployment-spi/src/main/java/io/quarkus/devui/spi/page/QuteDataPageBuilder.java","lineNumber":17,"sourceCode":"package io.quarkus.devui.spi.page;\n\npublic class QuteDataPageBuilder extends PageBuilder<QuteDataPageBuilder> {\n    private static final String DOT_HTML = \".html\";\n    private static final String QWC_DATA_QUTE_PAGE_JS = \"qwc-data-qute-page.js\";\n    private String templateLink;\n\n    protected QuteDataPageBuilder(String title) {\n        super();\n        super.title = title;\n        super.internalComponent = true;// As external page runs on \"internal\" namespace\n        super.componentLink = QWC_DATA_QUTE_PAGE_JS;\n    }\n\n    public QuteDataPageBuilder templateLink(String templateLink) {\n        if (templateLink == null || templateLink.isEmpty() || !templateLink.endsWith(DOT_HTML)) {\n            throw new RuntimeException(\n                    \"Invalid template link [\" + templateLink + \"] - Expeting a link that ends with .html\");\n        }\n\n        this.templateLink = templateLink;\n        return this;\n    }\n\n    @Override\n    public Page build() {\n\n        super.metadata(\"templatePath\", getTemplatePath());\n        return super.build();\n    }\n\n    public String getTemplatePath() {\n        return \"/dev-ui/\" + this.templateLink;\n    }\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/devui/deployment-spi/src/main/java/io/quarkus/devui/spi/page/QuteDataPageBuilder.java#L1-L35","documentation":"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.","triggerScenarios":"Calling quteDataPageBuilder().templateLink(\"templates/foo\") or templateLink(\"\") / templateLink(null) — i.e. missing the .html extension or passing an empty value.","commonSituations":"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.","solutions":["Append the extension: templateLink(\"templates/my-page.html\")","Reference templates that exist under META-INF/resources of the extension and end with .html","Normalize the input: if (link != null && !link.endsWith(\".html\")) link = link + \".html\"; before calling","Verify the file is present in the built artifact (check target/classes / the extension jar)"],"exampleFix":"// before\nquteDataPageBuilder().templateLink(\"templates/status\"); // throws\n// after\nquteDataPageBuilder().templateLink(\"templates/status.html\");","handlingStrategy":"validation","validationCode":"if (link == null || link.isBlank() || !link.endsWith(\".html\")) {\n    throw new IllegalStateException(\"templateLink must be a non-empty path ending in .html: \" + link);\n}","typeGuard":"boolean isValidTemplateLink(String l) {\n    return l != null && !l.isBlank() && l.toLowerCase().endsWith(\".html\");\n}","tryCatchPattern":"try {\n    quteDataPageBuilder().templateLink(link);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"Expeting a link that ends with .html\")) {\n        quteDataPageBuilder().templateLink(link + \".html\");\n    } else throw e;\n}","preventionTips":["Always pass paths ending in .html, never source .md/.qute files","Normalize suffixes before calling: if (!link.endsWith(\".html\")) link += \".html\"","Verify the template ships under META-INF/resources in the built jar","Keep template path constants in one place to avoid drift"],"tags":["devui","qute","template","validation"],"backgroundTag":"invalid-path-template","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}