Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qute: Rendering Timeout Instead of Throwing TemplateException for Missing Keys in {#let} and {#set} Constructs #44674

Closed
YassinHajaj opened this issue Nov 24, 2024 · 4 comments · Fixed by #44682
Assignees
Labels
area/qute The template engine kind/bug Something isn't working
Milestone

Comments

@YassinHajaj
Copy link

YassinHajaj commented Nov 24, 2024

Describe the bug

The rendering of a Qute template with specific {#let} or {#set} constructs results in a timeout instead of the expected exception when certain data is missing. The issue occurs when using TemplateInstance combined with data() method calls to pass data to the template.

I attempted to use the data() method to provide the required context for the template, but when the template tried to access a non-existent key, the operation timed out instead of immediately throwing a TemplateException. The issue is particularly evident with nested structures and the use of {#let} and {#set} constructs in Qute templates.

Expected behavior

When rendering a Qute template and a key referenced within the template is missing, the engine should throw a TemplateException with an appropriate message indicating that the key was not found.

For example:

  • Rendering error: Key "c" not found in the map with keys [a] in expression {c}

Actual behavior

Instead of throwing a TemplateException, the rendering operation times out with the message:

  • rendering timeout [10000ms] occurred.

This happens when using TemplateInstance in combination with either one of those:

  • The {#let} construct.
  • The {#set} construct.
  • A missing {/let} closing tag.

When debugging internally, I can see the exception being thrown in TemplateImpl#renderAsyncNoTimeout

Image

But still, the final exception is the timeout.

How to Reproduce?

Ensure you are using the Quarkus version 3.15.1.

Run the following test class

@QuarkusTest
class QuteTest {

    @Inject
    Engine templateEngine;

    private static final Map<String, Object> DATA = Map.of(
            "a", Map.of("b", Map.of())
    );

    @Test
    void withDataFactoryMethod() {
        TemplateInstance instance = templateEngine.parse("""
                {#let b = a.b}
                    {c}
                {/let}
                """).data(DATA);

        assertThatThrownBy(instance::render)
                .isInstanceOf(TemplateException.class)
                .hasRootCauseMessage("Rendering error: Key \"c\" not found in the map with keys [a] in expression {c}");
    }

    @Test
    void withInstanceThenDataForEachEntry() {
        TemplateInstance instance = templateEngine.parse("""
                {#let b = a.b}
                    {c}
                {/let}
                """).instance();
        for (var e : DATA.entrySet()) {
            instance.data(e.getKey(), e.getValue());
        }
        assertThatThrownBy(instance::render)
                .isInstanceOf(TemplateException.class)
                .hasMessageContaining("rendering timeout [10000ms] occured");
    }

    @Test
    void withSet_withInstanceThenDataForEachEntry() {
        TemplateInstance instance = templateEngine.parse("""
                {#set b = a.b}
                    {c}
                {/set}
                """).instance();
        for (var e : DATA.entrySet()) {
            instance.data(e.getKey(), e.getValue());
        }
        assertThatThrownBy(instance::render)
                .isInstanceOf(TemplateException.class)
                .hasMessageContaining("rendering timeout [10000ms] occured");
    }

    @Test
    void withLetWithoutEndTagwithInstanceThenDataForEachEntry() {
        TemplateInstance instance = templateEngine.parse("""
                {#let b = a.b}
                    {c}
                """).instance();
        for (var e : DATA.entrySet()) {
            instance.data(e.getKey(), e.getValue());
        }
        assertThatThrownBy(instance::render)
                .isInstanceOf(TemplateException.class)
                .hasMessageContaining("rendering timeout [10000ms] occured");
    }
}

Output of uname -a or ver

Darwin

Output of java -version

21.0.1

Quarkus version or git rev

3.15.1

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.1

Additional information

As you can imagine, this will lead to people investigating timeout issues and exploring timeout solutions instead of focusing on their actual issue.

@YassinHajaj YassinHajaj added the kind/bug Something isn't working label Nov 24, 2024
@quarkus-bot quarkus-bot bot added the area/qute The template engine label Nov 24, 2024
Copy link

quarkus-bot bot commented Nov 24, 2024

/cc @mkouba (qute)

@mkouba
Copy link
Contributor

mkouba commented Nov 25, 2024

Thanks for the report!

Indeed, we handle the missing properties inconsistently. For Map (QuteTest#withDataFactoryMethod()) it works as expected. However, for Mapper (all other test methods in the QuteTest) the original exception slips through the error handling and the returned CompletableFuture is never completed - hence the timeout exception.

This pull request should fix the problem: #44682

FTR this issue can only occur if strict rendering is enabled (the default).

@YassinHajaj
Copy link
Author

Makes perfect sense, thanks for the quick fix Martin !

@mkouba
Copy link
Contributor

mkouba commented Nov 25, 2024

Makes perfect sense, thanks for the quick fix Martin !

You're welcome 🙏

@quarkus-bot quarkus-bot bot added this to the 3.18 - main milestone Nov 25, 2024
@gsmet gsmet modified the milestones: 3.18 - main, 3.17.1 Nov 27, 2024
gsmet pushed a commit to gsmet/quarkus that referenced this issue Nov 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/qute The template engine kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants