run-llama/llama_index · error · ValueError
achat_stream is None. Cannot asynchronously write to history
Error message
achat_stream is None. Cannot asynchronously write to history without achat_stream.
What it means
StreamingAgentChatResponse.awrite_response_to_history() consumes the asynchronous LLM stream (self.achat_stream) to persist the final message into memory. achat_stream defaults to None, so the method raises immediately when no async stream was ever attached — typically because the response was produced by the synchronous path or built manually.
Source
Thrown at llama-index-core/llama_index/core/chat_engine/types.py:234
# This act as is_done events for any consumers waiting
self.is_function_not_none_thread_event.set()
if on_stream_end_fn is not None and not self.is_function:
on_stream_end_fn()
@dispatcher.span
async def awrite_response_to_history(
self,
memory: BaseMemory,
on_stream_end_fn: Optional[Callable] = None,
) -> None:
self._ensure_async_setup()
assert self.aqueue is not None
assert self.is_function_false_event is not None
assert self.new_item_event is not None
if self.achat_stream is None:
raise ValueError(
"achat_stream is None. Cannot asynchronously write to "
"history without achat_stream."
)
# try/except to prevent hanging on error
dispatcher.event(StreamChatStartEvent())
try:
final_text = ""
async for chat in self.achat_stream:
self.is_function = is_function(chat.message)
if chat.delta:
dispatcher.event(
StreamChatDeltaReceivedEvent(
delta=chat.delta,
)
)
self.aput_in_queue(chat.delta)
final_text += chat.delta or ""View on GitHub (pinned to afd0fef371)
Solutions
- Use the matching method: responses from stream_chat() need response.write_response_to_history(memory), responses from astream_chat() need await response.awrite_response_to_history(memory)
- If constructing the object yourself, set achat_stream: StreamingAgentChatResponse(achat_stream=llm.astream_chat(...))
- Prefer agent.astream_chat() end-to-end and simply iterate response.response_gen — history writing happens automatically
Example fix
// before
response = agent.stream_chat("hi")
await response.awrite_response_to_history(memory) # ValueError: achat_stream is None
// after
response = await agent.astream_chat("hi")
await response.awrite_response_to_history(memory) Defensive patterns
Strategy: validation
Validate before calling
if response.achat_stream is None:
raise RuntimeError("response has no async stream; use write_response_to_history") Type guard
from llama_index.core.chat_engine.types import StreamingAgentChatResponse
def has_async_stream(resp: StreamingAgentChatResponse) -> bool:
return resp.achat_stream is not None Try / catch
try:
await response.awrite_response_to_history(memory)
except ValueError as e:
if "achat_stream is None" in str(e):
response.write_response_to_history(memory) # sync fallback
else:
raise Prevention
- Keep the whole request path one flavor: astream_chat + awrite_response_to_history
- Lint for calls to sync agent methods inside async functions (ruff rule ASYNC / asyncio-dangling)
- Never construct StreamingAgentChatResponse without the stream you intend to consume
When it happens
Trigger: Calling await awrite_response_to_history(memory) on a response from agent.stream_chat() (sync — sets chat_stream only); calling it on a hand-constructed StreamingAgentChatResponse() without achat_stream; consuming achat_stream fully yourself and then calling the method.
Common situations: Calling sync agent methods inside async endpoints and then trying to use the async history writer; custom agent implementations that create StreamingAgentChatResponse() and forget to set achat_stream; porting sync example code to async half-way.
Related errors
- achat_stream is None!
- chat_stream is None. Cannot write to history without chat_st
- chat_stream is None!
- Streaming is not enabled. Please use achat() instead.
- Streaming is not enabled. Please use chat() instead.
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/2992483dbe22003a.
Report an issue: GitHub.