nodejs/node · error · TypeError

Loop length for some iterators cannot be lazily calculated…

Error message

Loop length for some iterators cannot be lazily calculated in async mode

What it means

Raised by AsyncLoopContext.length (asyncsupport.py) when loop.length / loop.revindex / loop.last and similar length-derived attributes are requested during async iteration but no upfront length was supplied. Unlike sync mode, an async iterator cannot be cheaply len()-ed, so the length is unknown and these attributes are unavailable.

Solutions

  1. Materialize the async iterator into a list before the loop so the length is known: `{% for x in await to_list(source) %}`.
  2. Pre-compute the length and pass it explicitly if the loop construct supports a length argument.
  3. Rewrite the template body to not depend on total count (use loop.index / loop.index0 only, which need no length).

Example fix

{# before #}
{% for x in async_source %}{{ loop.length }}{% endfor %}
{# after #}
{% set items = async_source | list %}
{% for x in items %}{{ items | length }}{% endfor %}
Defensive patterns

Strategy: validation

Validate before calling

async def materialize(ait):
    out = []
    async for x in ait:
        out.append(x)
    return out

# in template: {% set items = await to_list(source) %} then iterate `items`

Prevention

When it happens

Trigger: In an async-enabled template, iterating `{% for x in some_async_gen %}` and inside the loop body referencing `{{ loop.length }}`, `{{ loop.revindex }}`, `{{ loop.last }}`, or `{{ loop.first }}`-style helpers that need the total count.

Common situations: Iterating an async generator / async DB cursor in a template and trying to show 'item N of M' progress; reusing a sync template that used loop.length against a now-async data source.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/7671e199052e09f7. Report an issue: GitHub.

Appendix: source

Thrown at tools/inspector_protocol/jinja2/asyncsupport.py:202

            yield item
        return
    for item in iterable:
        yield item


class AsyncLoopContext(LoopContextBase):

    def __init__(self, async_iterator, undefined, after, length, recurse=None,
                 depth0=0):
        LoopContextBase.__init__(self, undefined, recurse, depth0)
        self._async_iterator = async_iterator
        self._after = after
        self._length = length

    @property
    def length(self):
        if self._length is None:
            raise TypeError('Loop length for some iterators cannot be '
                            'lazily calculated in async mode')
        return self._length

    def __aiter__(self):
        return AsyncLoopContextIterator(self)


class AsyncLoopContextIterator(object):
    __slots__ = ('context',)

    def __init__(self, context):
        self.context = context

    def __aiter__(self):
        return self

    async def __anext__(self):
        ctx = self.context

View on GitHub (pinned to 1b2de5e052)