langchain-ai/langchain · error · TypeError

AsyncTextProjection requires a string delta

Error message

AsyncTextProjection requires a string delta

What it means

`TypeError` from `AsyncTextProjection.push`: a producer pushed a delta that is not a `str` into the string-specialized async projection used for `.text`/`.reasoning` in streaming chat model code. The runtime check mirrors the sync version (errorIndex 73) and fails fast on producer API-contract violations.

Source

Thrown at libs/core/langchain_core/language_models/chat_model_stream.py:522

    async def __anext__(self) -> str:
        """Return the next text delta."""
        item = await super().__anext__()
        if not isinstance(item, str):
            msg = "AsyncTextProjection received a non-string delta"
            raise TypeError(msg)
        return item


class AsyncTextProjection(AsyncProjection):
    """String-specialized async projection for `.text` and `.reasoning`."""

    __slots__ = ()

    def push(self, delta: str) -> None:
        """Append a text delta and notify waiters."""
        if not isinstance(cast("Any", delta), str):
            msg = "AsyncTextProjection requires a string delta"
            raise TypeError(msg)
        super().push(delta)

    def complete(self, final_value: str) -> None:
        """Set the final accumulated text and notify waiters."""
        if not isinstance(cast("Any", final_value), str):
            msg = "AsyncTextProjection requires a string final value"
            raise TypeError(msg)
        super().complete(final_value)

    def __aiter__(self) -> _AsyncTextProjectionIterator:
        """Return an async iterator over text deltas."""
        return _AsyncTextProjectionIterator(self)

    def __await__(self) -> Generator[Any, None, str]:
        """Await the full accumulated text."""
        return self._await_text_impl().__await__()

    async def _await_text_impl(self) -> str:

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Push the extracted string: `projection.push(chunk.text)`; guard optional content first (`if chunk.text: ...`).
  2. Type your producer code so `push` only ever sees `str` (mypy will catch violations at development time).
  3. Use the generic `AsyncProjection` if you must push non-string values.

Example fix

# before
projection.push(chunk)  # non-string AIMessageChunk

# after
if chunk.text:
    projection.push(chunk.text)
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(delta, str), f"delta must be str, got {type(delta).__name__}"
projection.push(delta)

Type guard

def is_text_delta(v: object) -> bool:
    """True when v can be pushed into an AsyncTextProjection."""
    return isinstance(v, str)

Try / catch

null

Prevention

When it happens

Trigger: Adapter/integration code calling `projection.push(value)` with an `AIMessageChunk`, `None`, bytes, or a dict instead of the extracted string. Typically happens in custom chat model implementations or when reusing the streaming internals directly.

Common situations: Custom async model integration pushing whole chunks instead of `chunk.text`; forgetting None-checks on optional chunk fields; porting sync adapter code that used untyped buffers.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/0e163a6ae3431970. Report an issue: GitHub.