{"record":{"id":"9a7280c411212a81","repo":"run-llama/llama_index","slug":"chat-stream-is-none","errorCode":null,"errorMessage":"chat_stream is None!","messagePattern":"chat_stream is None!","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/chat_engine/types.py","lineNumber":307,"sourceCode":"    @property\n    def response_gen(self) -> Generator[str, None, None]:\n        try:\n            yielded_once = False\n            if self.is_writing_to_memory:\n                while not self.is_done or not self.queue.empty():\n                    if self.exception is not None:\n                        raise self.exception\n\n                    try:\n                        delta = self.queue.get(block=False)\n                        self.unformatted_response += delta\n                        yield delta\n                        yielded_once = True\n                    except Empty:\n                        time.sleep(0)\n            else:\n                if self.chat_stream is None:\n                    raise ValueError(\"chat_stream is None!\")\n\n                for chat_response in self.chat_stream:\n                    self.unformatted_response += chat_response.delta or \"\"\n                    yield chat_response.delta or \"\"\n                    yielded_once = True\n\n            self.response = self.unformatted_response.strip()\n\n            if not yielded_once:\n                yield self.response\n        finally:\n            if self.write_response_to_history_thread is not None:\n                self.write_response_to_history_thread.join()\n                self.write_response_to_history_thread = None\n\n    async def async_response_gen(self) -> AsyncGenerator[str, None]:\n        try:\n            yielded_once = False","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/chat_engine/types.py#L289-L325","documentation":"When a StreamingAgentChatResponse has is_writing_to_memory=False, its sync response_gen property iterates the raw LLM stream (self.chat_stream) instead of the internal queue. chat_stream defaults to None, so iterating response_gen in that state means no stream was ever attached — usually a sync/async mix-up or a hand-built object.","triggerScenarios":"Iterating response.response_gen on an object where is_writing_to_memory=False and chat_stream is None — e.g. a response from agent.astream_chat() consumed synchronously, or a manually constructed StreamingAgentChatResponse() with no chat_stream argument.","commonSituations":"Custom agent subclasses that set is_writing_to_memory=False; reusing one response object across sync and async consumers; copying example code that manipulates these flags.","solutions":["Get the response from the sync agent.stream_chat() so chat_stream is populated, and iterate its response_gen","For async flows use `async for token in response.async_response_gen()` instead of the sync generator","If building the object manually, pass chat_stream=llm.stream_chat(...) or keep is_writing_to_memory=True so the queue path is used"],"exampleFix":"// before\nresponse = await agent.astream_chat(\"hi\")\nfor token in response.response_gen:  # ValueError: chat_stream is None!\n    print(token)\n\n// after\nresponse = await agent.astream_chat(\"hi\")\nasync for token in response.async_response_gen():\n    print(token)","handlingStrategy":"validation","validationCode":"if not response.is_writing_to_memory and response.chat_stream is None:\n    raise RuntimeError(\"no queue path and no chat_stream; cannot sync-iterate\")","typeGuard":"def can_sync_iterate(resp) -> bool:\n    return resp.is_writing_to_memory or resp.chat_stream is not None","tryCatchPattern":"try:\n    for token in response.response_gen:\n        print(token, end=\"\")\nexcept ValueError as e:\n    if \"chat_stream is None\" in str(e):\n        print(response.response)\n    else:\n        raise","preventionTips":["Only iterate response_gen from responses produced by the matching sync engine call","In custom agents keep is_writing_to_memory=True unless you also attach the raw stream","Centralize token-iteration in one utility so the sync/async contract is enforced once"],"tags":["streaming","chat-engine","agents","sync-async-mismatch"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}