{"record":{"id":"eeae2451aa3ec526","repo":"langchain-ai/langchain","slug":"asynctextprojection-received-a-non-string-delta","errorCode":null,"errorMessage":"AsyncTextProjection received a non-string delta","messagePattern":"AsyncTextProjection received a non-string delta","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/language_models/chat_model_stream.py","lineNumber":509,"sourceCode":"                    if proj.error is not None:\n                        raise proj.error\n                    raise StopAsyncIteration\n            else:\n                proj._event.clear()  # noqa: SLF001\n                await proj._event.wait()  # noqa: SLF001\n\n\nclass _AsyncTextProjectionIterator(_AsyncProjectionIterator):\n    \"\"\"Async iterator over an `AsyncTextProjection`'s text deltas.\"\"\"\n\n    __slots__ = ()\n\n    async def __anext__(self) -> str:\n        \"\"\"Return the next text delta.\"\"\"\n        item = await super().__anext__()\n        if not isinstance(item, str):\n            msg = \"AsyncTextProjection received a non-string delta\"\n            raise TypeError(msg)\n        return item\n\n\nclass AsyncTextProjection(AsyncProjection):\n    \"\"\"String-specialized async projection for `.text` and `.reasoning`.\"\"\"\n\n    __slots__ = ()\n\n    def push(self, delta: str) -> None:\n        \"\"\"Append a text delta and notify waiters.\"\"\"\n        if not isinstance(cast(\"Any\", delta), str):\n            msg = \"AsyncTextProjection requires a string delta\"\n            raise TypeError(msg)\n        super().push(delta)\n\n    def complete(self, final_value: str) -> None:\n        \"\"\"Set the final accumulated text and notify waiters.\"\"\"\n        if not isinstance(cast(\"Any\", final_value), str):","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/language_models/chat_model_stream.py#L491-L527","documentation":"`TypeError` from the async iterator of `AsyncTextProjection` (`async for delta in projection.text`): an item delivered from the projection's queue is not a string. It is the async counterpart of errorIndex 75 — a runtime check that catches non-string deltas that bypassed the typed `push` (e.g. via the untyped base `AsyncProjection.push`).","triggerScenarios":"Producer code calling `AsyncProjection.push(non_str)` (base class) or an overriding subclass omitting the type check, followed by `async for delta in projection:` consuming the corrupted buffer. Affects `.text` and `.reasoning` async projections in streaming chat model code.","commonSituations":"Custom async model adapters pushing AIMessageChunk objects or `None` into `.text`; subclasses of `AsyncTextProjection` that override `push` without validation; migration from dict-based accumulation where values were sometimes non-string.","solutions":["Push only strings through the typed `AsyncTextProjection.push` (validates on entry — errorIndex 78's guard): `await-safe projection.push(chunk.text)`.","Guard optional fields before pushing: `if chunk.text: projection.push(chunk.text)`.","Remove direct base-class `push`/`complete` calls from your adapter."],"exampleFix":"# before\nprojection.AsyncProjection.push(chunk)  # bypasses type check\nasync for delta in projection: ...  # TypeError\n\n# after\nif chunk.text:\n    projection.push(chunk.text)\nasync for delta in projection: ...","handlingStrategy":"type-guard","validationCode":"assert isinstance(item, str), f\"async text delta must be str, got {type(item).__name__}\"\n# push-side validation prevents this entirely:\nif isinstance(delta, str):\n    projection.push(delta)","typeGuard":"def is_async_text_delta(v: object) -> bool:\n    \"\"\"True when v is a valid AsyncTextProjection delta.\"\"\"\n    return isinstance(v, str)","tryCatchPattern":"null","preventionTips":["Push strings only via the typed async push","Do not override push/complete on AsyncTextProjection without re-adding the isinstance checks","Cover async iteration in adapter unit tests"],"tags":["streaming","async","typeerror","internal-api"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}