Skip to content

Fix: Handle nested premature NJK template content errors - #4352

Open
khawkins98 wants to merge 2 commits into
11ty:mainfrom
khawkins98:fix/nested-premature-template-content-error
Open

Fix: Handle nested premature NJK template content errors#4352
khawkins98 wants to merge 2 commits into
11ty:mainfrom
khawkins98:fix/nested-premature-template-content-error

Conversation

@khawkins98

Copy link
Copy Markdown

tl;dr: This adds better error handling in the new v4 NJK template rendering + tests.

In Eleventy 4.0.0-alpha.10 with @11ty/nunjucks 4.0.0-alpha.3, a TemplateContentPrematureUseError thrown inside a Nunjucks filter can be wrapped in more than one Error.cause layer. Eleventy uses that error as a signal that a template has asked for another template’s rendered content too early: it normally catches the signal, renders the dependency, and tries again. Once Nunjucks has wrapped the error several layers deep, Eleventy no longer recognizes it and stops the build instead of retrying.

Conceptually, the error changes from this:

TemplateContentPrematureUseError

to something like this:

Nunjucks render error
└── Nunjucks filter error
    └── TemplateContentPrematureUseError

The existing check recognizes the original error and one Error.cause wrapper, but not the additional nesting. This change recursively checks the recognized wrapper paths until it finds the original retry signal.

Conceptually, the check changes from this:

Is this the retry signal?
If not, is its immediate cause the retry signal?

to this:

Start with the outer error.
Check whether it is the retry signal.
Follow its standard Error.cause link and repeat.
At each level, also retain Eleventy’s guarded Liquid error path.
Stop when the signal is found or all recognized paths have been checked.

This allows any number of normal Error.cause wrappers while the repeated-error check prevents an accidental cycle from looping forever. It does not treat every arbitrary originalError property as a wrapper.

Reproduction

Minimal reproduction: https://github.com/khawkins98/eleventy-v4-template-content-repro

The reproduction uses a synchronous Nunjucks filter that reads templateContent from a tagged collection:

  • Unpatched Eleventy 4.0.0-alpha.10 fails with a wrapped TemplateContentPrematureUseError.
  • Catching the error defensively makes the build pass but incorrectly renders 0.
  • Applying this change to the public reproduction allows Eleventy’s normal retry path to complete, producing the expected result, 6.

Implementation

ErrorUtil.isPrematureTemplateContentError() now walks nested Error.cause values with cycle protection.

The existing guarded Liquid originalError.originalError path remains restricted to RenderError and UndefinedVariableError; the same guarded check is now available beneath standard Error.cause wrappers. The implementation does not follow arbitrary originalError properties.

This extends the approach previously accepted in #3651, which added support for one level of Error.cause while retaining the Liquid guards.

Tests

  • Added a regression test confirming that ErrorUtil recognizes a TemplateContentPrematureUseError after it passes through a Nunjucks filter.
  • Added coverage for cyclic Error.cause graphs.
  • npm run test:server: 1,438 passed, 28 skipped.
  • npm run check: no errors; 25 pre-existing warnings.

Alternatives

The Nunjucks integration could instead preserve the original retry signal at its wrapping boundary. I used recursive detection here because Eleventy already centralizes template-engine-specific recognition in ErrorUtil, and #3651 established Error.cause handling there. I am happy to adjust this if a fix in @11ty/nunjucks is preferred.

Disclaimer

AI assistance was used to help reduce and test the reproduction and prepare this change.

@khawkins98
khawkins98 requested a review from zachleat as a code owner August 27, 2026 09:09
@khawkins98 khawkins98 changed the title Fix/nested premature template content error Fix: Handle nested premature NJK template content errors Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant