langchain-ai/langgraph · error · TypeError

This StreamChannel is bound to async mode — use 'async for'…

Error message

This StreamChannel is bound to async mode — use 'async for' instead.

What it means

Raised by StreamChannel.__iter__ when a sync iteration is attempted on a channel whose mode flag _is_async is True. The channel was bound to async mode when its transformer was registered with a StreamMux, so its data is driven by an async pump; consuming it with a plain for loop or next() is a mode mismatch, not a state error. The fix is to consume via 'async for' (i.e. __aiter__/__anext__), or rebind the transformer to a sync mux.

Solutions

  1. Use `async for item in ch` on async-bound channels
  2. Run the graph with sync stream() so the channel binds to sync mode
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at libs/langgraph/langgraph/stream/stream_channel.py:172 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of langchain-ai/langgraph@38031739e5 (2026-08-26). Data as JSON: /api/errors/8f066a0650cf9828. Report an issue: GitHub.

Appendix: source

Thrown at libs/langgraph/langgraph/stream/stream_channel.py:172

    # ------------------------------------------------------------------
    # Sync iteration (caller-driven pump)
    # ------------------------------------------------------------------

    def __iter__(self) -> Iterator[T]:
        """Subscribe and return a sync cursor. Can be called only once.

        Raises:
            TypeError: If the channel is unbound or bound to async mode.
            RuntimeError: If the channel already has a subscriber.
        """
        if self._is_async is None:
            raise TypeError(
                "StreamChannel has not been bound yet. "
                "Register the transformer with a StreamMux first."
            )
        if self._is_async:
            raise TypeError(
                "This StreamChannel is bound to async mode — use 'async for' instead."
            )
        if self._subscribed:
            raise RuntimeError(
                "StreamChannel already has a subscriber; use .tee(n) for fan-out."
            )
        self._subscribed = True
        return self._sync_cursor()

    def _sync_cursor(self) -> Iterator[T]:
        while True:
            if self._items:
                _stamp, item = self._items.popleft()
                yield item
            elif self._closed:
                if self._error is not None:
                    raise self._error
                return

View on GitHub (pinned to 38031739e5)