langchain-ai/langchain · error · TypeError

SyncTextProjection requires a string delta

Error message

SyncTextProjection requires a string delta

What it means

`TypeError` from `SyncTextProjection.push` (the string-specialized streaming buffer behind `.text`/`.reasoning` projections in `chat_model_stream`): a producer pushed a delta that is not a `str` (e.g. an `AIMessageChunk`, bytes, or `None`). The projection API is typed for strings only and enforces this at runtime to fail fast on producer bugs.

Source

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

        if self._error is not None:
            raise self._error
        return self._final_value


class SyncTextProjection(SyncProjection):
    """String-specialized sync projection.

    Adds typed string producers and consumers, plus `__str__`, `__bool__`,
    `__repr__` for ergonomic use with `.text` and `.reasoning` projections.
    """

    __slots__ = ()

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

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

    def __iter__(self) -> Iterator[str]:
        """Yield text deltas, raising if a producer supplied a non-string value."""
        for delta in super().__iter__():
            if not isinstance(delta, str):
                msg = "SyncTextProjection received a non-string delta"
                raise TypeError(msg)
            yield delta

    def get(self) -> str:

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. At the push site, push the extracted string: `projection.push(chunk.text)` or `projection.push(str_value)` — never the chunk object.
  2. Guard optional content: `if chunk.text: projection.push(chunk.text)`.
  3. If you genuinely need to push non-string values, use the generic `SyncProjection` rather than `SyncTextProjection`.

Example fix

# before
projection.push(chunk)  # AIMessageChunk is not a str

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

Strategy: type-guard

Validate before calling

assert isinstance(delta, str), f"text 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 a SyncTextProjection."""
    return isinstance(v, str)

Try / catch

null

Prevention

When it happens

Trigger: Internal/extension code calling `projection.push(delta)` with a non-string — e.g. pushing a chat-model chunk object or `None` instead of `chunk.text`. This is an API-contract violation by the producer (usually custom model adapter code or misuse of the streaming internals), not by end users.

Common situations: Writing a custom chat model integration and pushing raw AIMessageChunk objects into `.text`; forgetting a `None` check for optional fields (e.g. `chunk.tool_call_chunks`) before pushing; porting code from the generic `SyncProjection` (untyped) to `SyncTextProjection`.

Related errors


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