langchain-ai/langchain · error · TypeError
SyncTextProjection received a non-string delta
Error message
SyncTextProjection received a non-string delta
What it means
`TypeError` raised while iterating a `SyncTextProjection` (`for delta in projection`): a delta already sitting in the buffer is not a string. This is a second line of defense — even if a non-string slipped past `push` (possible via the untyped base class `SyncProjection.push`), iteration refuses to yield it to string-typed consumers.
Source
Thrown at libs/core/langchain_core/language_models/chat_model_stream.py:311
"""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:
"""Drain and return the full accumulated string, or empty if unfinished."""
value = super().get()
if value is None:
return ""
if not isinstance(value, str):
msg = "SyncTextProjection received a non-string final value"
raise TypeError(msg)
return value
def __str__(self) -> str:
"""Drain and return the full accumulated string."""
return self.get()
def __bool__(self) -> bool:
"""Return whether any deltas have been pushed."""View on GitHub (pinned to e32fa9a52e)
Solutions
- Find the producer that inserted the non-string and fix it to push strings only (use the typed `SyncTextProjection.push`, which validates on entry — errorIndex 73's guard).
- Do not bypass the typed API: never call `SyncProjection.push` directly on a text projection.
- If mixed value types are legitimate, iterate the generic projection and stringify per item yourself.
Example fix
# before: bypassing the typed push projection.SyncProjection.push(chunk) # non-str enters buffer for delta in projection: ... # TypeError here # after projection.push(chunk.text or "") for delta in projection: ...
Defensive patterns
Strategy: type-guard
Validate before calling
# Validate buffer contents before iterating (detects bad producers early)
for d in list(projection._deltas):
assert isinstance(d, str), f"non-string delta in buffer: {d!r}" Type guard
def text_projection_is_clean(proj) -> bool:
"""True when every buffered delta is a str (safe to iterate)."""
return all(isinstance(d, str) for d in proj._deltas) Try / catch
null
Prevention
- Route all writes through the typed push() so non-strings never enter the buffer
- Never bypass the typed override via base-class push
- Add unit tests that iterate after mixed producer paths
When it happens
Trigger: Calling `super().push(non_str)` on the base `SyncProjection` (bypassing the typed override), then iterating the projection; or sharing the underlying buffer between a generic and a text projection where one producer pushed a non-string.
Common situations: Subclassing `SyncTextProjection` and overriding `push` without the isinstance check; adapter code that mixes base-class pushes with text-projection iteration; corrupted producer state after an upstream exception handler pushes a sentinel object.
Related errors
- SyncTextProjection requires a string delta
- SyncTextProjection requires a string final value
- SyncTextProjection received a non-string final value
- AsyncTextProjection received a non-string delta
- AsyncTextProjection requires a string delta
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/1566a38113db7a5f.
Report an issue: GitHub.