langchain-ai/langchain · error · TypeError
AsyncTextProjection requires a string final value
Error message
AsyncTextProjection requires a string final value
What it means
`TypeError` from `AsyncTextProjection.complete`: the producer's final value is not a `str`. `complete` closes the async projection and wakes all awaiters (`await projection.text`); a non-string final value would flow into every consumer, so it is rejected at the source.
Source
Thrown at libs/core/langchain_core/language_models/chat_model_stream.py:529
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:
"""Return accumulated text or raise if the final value is not a string."""
value = await self._await_impl()
if value is None:
return ""
if not isinstance(value, str):
msg = "AsyncTextProjection received a non-string final value"
raise TypeError(msg)View on GitHub (pinned to e32fa9a52e)
Solutions
- Always complete with a string; use `complete("")` for empty streams.
- Convert at the completion site: `projection.complete(msg.content if isinstance(msg.content, str) else "")`.
- Ensure every termination path (success, error, cancellation) in the producer completes with a str or leaves the projection incomplete.
Example fix
# before projection.complete(final_message) # not a str # after projection.complete(final_message.text or "")
Defensive patterns
Strategy: type-guard
Validate before calling
final = final_value if isinstance(final_value, str) else "" projection.complete(final)
Type guard
def is_final_text(v: object) -> bool:
"""True when v is acceptable as an AsyncTextProjection final value."""
return isinstance(v, str) Try / catch
null
Prevention
- Always complete with a str; "" for empty output
- Ensure error/cancellation paths also complete with a string or not at all — never a sentinel object
- Never call the untyped base AsyncProjection.complete on a text projection
When it happens
Trigger: Adapter code calling `projection.complete(value)` with a message object, `None`, or bytes instead of the final text — e.g. `complete(final_message)` or `complete(None)` for an empty stream — inside a custom async chat model integration.
Common situations: Completing `.text` with `AIMessage` instead of `AIMessage.content`/`.text`; empty-stream paths completing with `None`; exception handlers completing projections with sentinel objects.
Related errors
- AsyncTextProjection received a non-string delta
- AsyncTextProjection requires a string delta
- 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/623d09438f0b7772.
Report an issue: GitHub.