Skip to content

Renoir template engine bug affecting py4web — [[ ]] block nested if causes cryptic error #1048

@jeffreyheping

Description

@jeffreyheping

Hi Massimo,

Thank you for py4web — I've been using it for a teaching project that helps developers transition from ASP Classic to Python web development. The framework's simplicity and "batteries included" approach have been a great fit for this audience.

I wanted to bring to your attention a bug in the Renoir templating engine (v1.9.0, bundled with py4web) that affects py4web users in a particularly painful way.


The Problem

When a single [[ ]] block contains a nested if statement, the template fails with:

TemplateError: missing "pass" in view

Example that triggers the bug:

[[
x = 1
if x:
    y = 2
    if y:
        pass
]]
<p>Hello</p>

Single-level if inside [[ ]] works fine. Cross-block [[if:]]...[[pass]] also works fine. It's only nested if inside a single [[ ]] block that breaks.

Why This Hits py4web Users Hard

There are two compounding issues:

1. The error message is almost useless for debugging

reindent() raises TemplateError('missing "pass" in view', self.name, 1) — the 1 is a hardcoded line number, not the actual location of the problem. When this error hits in py4web, all the user sees is a ticket page with no useful information about which template, which line, or what went wrong.

For developers learning py4web (especially those coming from ASP Classic, where <% %> blocks with nested logic are normal), this error is extremely confusing. The template looks syntactically correct, the error message points to the wrong line, and there's no indication that the issue is with block nesting.

2. The recommended cross-block style is a non-obvious paradigm shift

In ASP Classic, developers routinely write:

<%
If x Then
    If y Then
        ' do something
    End If
End If
%>

The natural translation to py4web would be a single [[ ]] block with nested if, which silently fails. The "correct" cross-block style ([[if x:]]...[[if y:]]...[[pass]][[pass]]) is a fundamental paradigm difference that isn't obvious from the error message.


What I've Done

I've traced the root cause to TemplateParser.reindent() in Renoir's renoir/parsing/parsers.py. The method uses a simple counter to track indentation levels (: → +1, pass → -1), but it has no awareness of [[ ]] block boundaries. When a block ends with an unclosed if, the ]] delimiter acts as an implicit pass that the counter can't see.

I've filed an issue on the Renoir repository with a full root cause analysis and fix suggestions:

emmett-framework/renoir#10


Suggestion for py4web

Even if the upstream fix takes time, there are two things that could significantly improve the experience for py4web users:

  1. Better error messages: Even a simple change like including the reindented code in the error output, or reporting the actual line where the indent counter went out of sync, would save users hours of debugging.

  2. Documentation note: A brief mention in the py4web templating docs that nested if inside a single [[ ]] block is not supported (and will produce a confusing error) would help newcomers avoid this trap entirely.

Thank you for your time, and for building such an approachable framework. I'm happy to help with testing or documentation if needed.

Best regards,
Jeffrey

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions