{"record":{"id":"30c0c6b10270416f","repo":"langchain-ai/langchain","slug":"synctextprojection-requires-a-string-final-value","errorCode":null,"errorMessage":"SyncTextProjection requires a string final value","messagePattern":"SyncTextProjection requires a string final value","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/language_models/chat_model_stream.py","lineNumber":303,"sourceCode":"\n    Adds typed string producers and consumers, plus `__str__`, `__bool__`,\n    `__repr__` for ergonomic use with `.text` and `.reasoning` projections.\n    \"\"\"\n\n    __slots__ = ()\n\n    def push(self, delta: str) -> None:\n        \"\"\"Append a text delta.\"\"\"\n        if not isinstance(cast(\"Any\", delta), str):\n            msg = \"SyncTextProjection 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 mark the projection as done.\"\"\"\n        if not isinstance(cast(\"Any\", final_value), str):\n            msg = \"SyncTextProjection requires a string final value\"\n            raise TypeError(msg)\n        super().complete(final_value)\n\n    def __iter__(self) -> Iterator[str]:\n        \"\"\"Yield text deltas, raising if a producer supplied a non-string value.\"\"\"\n        for delta in super().__iter__():\n            if not isinstance(delta, str):\n                msg = \"SyncTextProjection received a non-string delta\"\n                raise TypeError(msg)\n            yield delta\n\n    def get(self) -> str:\n        \"\"\"Drain and return the full accumulated string, or empty if unfinished.\"\"\"\n        value = super().get()\n        if value is None:\n            return \"\"\n        if not isinstance(value, str):\n            msg = \"SyncTextProjection received a non-string final value\"\n            raise TypeError(msg)","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/language_models/chat_model_stream.py#L285-L321","documentation":"`TypeError` from `SyncTextProjection.complete`: the final accumulated value supplied by the producer is not a `str` (e.g. a message object, `None`, or bytes). `complete(final_value)` closes the projection with the definitive text; passing anything else breaks every consumer (`get`, `__str__`, iteration), so it is rejected immediately.","triggerScenarios":"Producer code calling `projection.complete(final_text)` with a non-string — e.g. `complete(message)` where `message` is an `AIMessage`, or `complete(None)` when a stream produced no final text.","commonSituations":"Custom model adapters completing `.text` with the full message object instead of `message.content`; defensive `complete(result or None)` patterns where `None` flows in when the stream ended empty; refactors from dict-based buffers to the typed projection.","solutions":["Always complete with a string; for empty streams use `complete(\"\")`.","Convert explicitly at the completion site: `projection.complete(msg.content if isinstance(msg.content, str) else \"\")`.","Audit producers that branch on stream termination to ensure every path passes a string."],"exampleFix":"# before\nprojection.complete(final_message)  # AIMessage, not str\n\n# after\nprojection.complete(final_message.text or \"\")","handlingStrategy":"type-guard","validationCode":"final = final_value if isinstance(final_value, str) else \"\"\nprojection.complete(final)","typeGuard":"def is_final_text(v: object) -> bool:\n    \"\"\"True when v is acceptable as a SyncTextProjection final value.\"\"\"\n    return isinstance(v, str)","tryCatchPattern":"null","preventionTips":["Always complete with a str; use \"\" for empty streams","Complete at exactly one place in the producer (a finally block) with a validated string","Never call the untyped base SyncProjection.complete on a text projection"],"tags":["streaming","typeerror","internal-api"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}