nodejs/node · error · RuntimeError
Async mode requires a body stream to be passed to a template
Error message
Async mode requires a body stream to be passed to a template module. Use the async methods of the API you are using.
What it means
TemplateModule wraps an imported template (created via {% import %} or Environment.get_template().module). Its constructor must materialize the rendered output: normally it does list(template.root_render_func(context)), but in an async environment root_render_func is an async generator that cannot be drained synchronously. Therefore Jinja2 refuses to construct the module without a pre-collected body_stream.
Source
Thrown at tools/inspector_protocol/jinja2/environment.py:1148
def __repr__(self):
if self.name is None:
name = 'memory:%x' % id(self)
else:
name = repr(self.name)
return '<%s %s>' % (self.__class__.__name__, name)
@implements_to_string
class TemplateModule(object):
"""Represents an imported template. All the exported names of the
template are available as attributes on this object. Additionally
converting it into an unicode- or bytestrings renders the contents.
"""
def __init__(self, template, context, body_stream=None):
if body_stream is None:
if context.environment.is_async:
raise RuntimeError('Async mode requires a body stream '
'to be passed to a template module. Use '
'the async methods of the API you are '
'using.')
body_stream = list(template.root_render_func(context))
self._body_stream = body_stream
self.__dict__.update(context.get_exported())
self.__name__ = template.name
def __html__(self):
return Markup(concat(self._body_stream))
def __str__(self):
return concat(self._body_stream)
def __repr__(self):
if self.__name__ is None:
name = 'memory:%x' % id(self)
else:View on GitHub (pinned to 1b2de5e052)
Solutions
- Render via the async API so Jinja2 collects the body stream for you: use await template.render_async() / async for chunk in template.generate_async(), and access the imported module through await template.make_module_async() (or context_vars) instead of the synchronous .module property.
- If you only need macros, inline them or pass rendered strings rather than importing a module under enable_async.
- If async is not actually required, construct the Environment without enable_async (the default) so the synchronous module path works.
- Bump/verify your Jinja2 version supports the async module API (make_module_async / generate_async); older vendored copies may lack it.
Example fix
// before
env = Environment(loader=..., enable_async=True)
tmpl = env.get_template('page.html')
mod = tmpl.module # raises: async mode requires a body stream
// after
env = Environment(loader=..., enable_async=True)
tmpl = env.get_template('page.html')
mod = await tmpl.make_module_async() # body stream collected asynchronously Defensive patterns
Strategy: validation
Validate before calling
from jinja2 import Environment
def safe_module(env, name):
tmpl = env.get_template(name)
if env.is_async:
raise RuntimeError(
'cannot access .module synchronously under enable_async; '
'await tmpl.make_module_async() instead')
return tmpl.module Type guard
def supports_sync_module(env: Environment) -> bool:
return not getattr(env, 'is_async', False) Try / catch
try:
mod = tmpl.module
except RuntimeError as e:
if 'Async mode' in str(e):
raise RuntimeError('await tmpl.make_module_async() under enable_async') from e
raise Prevention
- Decide upfront whether your Environment is async; never mix .module access with enable_async=True.
- Centralize template import/module access in one helper that branches on env.is_async.
- When enabling enable_async, audit every {% import %} and .module usage site.
When it happens
Trigger: Constructing a TemplateModule synchronously (or calling .module on a template) while Environment(enable_async=True) is set and no body_stream was pre-collected via the async render path. Typically hit when mixing {% import 'macros.html' as m %} with an async environment, or calling template.module instead of await template.make_module_async().
Common situations: Adopting async rendering under asyncio/Starlette/Sanic/aiohttp and reusing existing {% import %} macros; upgrading a sync Jinja2 codebase to enable_async=True without converting the import/module access sites.
Related errors
- The environment was not created with async mode enabled.
- Template module attribute is unavailable in async mode
- Loop length for some iterators cannot be lazily calculated i
- This feature is not available for this version of Python
- can't write empty bucket
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/6a6ac33c7b4c4811.
Report an issue: GitHub.