microsoft/semantic-kernel · error · AgentThreadOperationException

Cannot retrieve chat history, since the thread has been dele

Error message

Cannot retrieve chat history, since the thread has been deleted.

What it means

Thrown by AutoGenConversableAgentThread.get_messages when the thread's _is_deleted flag is True. Once delete() has run, the in-memory chat history is cleared and the thread is marked deleted, so any subsequent attempt to read messages is rejected as an invalid operation on a dead thread.

Source

Thrown at python/semantic_kernel/agents/autogen/autogen_conversable_agent.py:89

        """Called when a new message has been contributed to the chat."""
        if isinstance(new_message, str):
            new_message = ChatMessageContent(role=AuthorRole.USER, content=new_message)

        if (
            not new_message.metadata
            or "thread_id" not in new_message.metadata
            or new_message.metadata["thread_id"] != self._id
        ):
            self._chat_history.add_message(new_message)

    async def get_messages(self) -> AsyncIterable[ChatMessageContent]:
        """Retrieve the current chat history.

        Returns:
            An async iterable of ChatMessageContent.
        """
        if self._is_deleted:
            raise AgentThreadOperationException("Cannot retrieve chat history, since the thread has been deleted.")
        if self._id is None:
            await self.create()
        for message in self._chat_history.messages:
            yield message

    async def reduce(self) -> ChatHistory | None:
        """Reduce the chat history to a smaller size."""
        if self._id is None:
            raise AgentThreadOperationException("Cannot reduce chat history, since the thread is not currently active.")
        if not isinstance(self._chat_history, ChatHistoryReducer):
            return None
        return await self._chat_history.reduce()


@experimental
class AutoGenConversableAgent(Agent):
    """A Semantic Kernel wrapper around an AutoGen 0.2 `ConversableAgent`.

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Do not call get_messages after delete(); reorder logic so reads happen before cleanup.
  2. Create a fresh thread (new AutoGenConversableAgentThread) if you need history after deletion.
  3. Track deletion state in your own code and short-circuit reads when deleted.

Example fix

# before
await thread.delete()
msgs = [m async for m in thread.get_messages()]

# after
msgs = [m async for m in thread.get_messages()]
await thread.delete()
Defensive patterns

Strategy: validation

Validate before calling

if thread._is_deleted:
    raise RuntimeError('thread already deleted; cannot read messages')

Type guard

def thread_is_readable(thread) -> bool:
    return not getattr(thread, '_is_deleted', False)

Try / catch

from semantic_kernel.exceptions.agent_exceptions import AgentThreadOperationException
try:
    messages = [m async for m in thread.get_messages()]
except AgentThreadOperationException as e:
    if 'has been deleted' in str(e):
        messages = []
    else:
        raise

Prevention

When it happens

Trigger: Calling `async for m in thread.get_messages()` after `await thread.delete()`; reusing a thread reference that another code path already deleted.

Common situations: Cleanup-then-inspect flow in tests or shutdown hooks; shared thread object deleted by a finally block before a later read; chaining agents where one deletes the thread.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/2502226b0b7ae1b2. Report an issue: GitHub.