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
- Push the extracted string: `projection.push(chunk.text)`; guard optional content first (`if chunk.text: ...`).
- Type your producer code so `push` only ever sees `str` (mypy will catch violations at development time).
- 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
- Push chunk.text (guarded), never the chunk object
- Type-hint producer callbacks as str-only
- Keep one push helper per adapter so validation lives in one place
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
- AsyncTextProjection received a non-string delta
- AsyncTextProjection requires a string final value
- SyncTextProjection requires a string delta
- SyncTextProjection requires a string final value
- SyncTextProjection received a non-string delta
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/0e163a6ae3431970.
Report an issue: GitHub.