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

Raised by the chat-completion AgentThread.get_messages (an AgentThreadOperationException) when self._is_deleted is true. Once the thread is deleted, the in-memory chat history is no longer accessible through this thread handle, so retrieval is blocked.

Source

Thrown at python/semantic_kernel/agents/chat_completion/chat_completion_agent.py:101

        """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()


@register_agent_type("chat_completion_agent")
class ChatCompletionAgent(DeclarativeSpecMixin, Agent):
    """A Chat Completion Agent based on ChatCompletionClientBase."""

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Do not call get_messages after delete; obtain a fresh thread for a new conversation.
  2. Track deletion state in your code and skip reads once the thread is deleted.
  3. Move any history inspection before the delete call.
  4. If you need history after deletion, persist it before deleting.

Example fix

// before
await thread.delete()
msgs = [m async for m in thread.get_messages()]  # raises
// after
msgs = [m async for m in thread.get_messages()]  # read first
await thread.delete()
Defensive patterns

Strategy: validation

Validate before calling

if thread._is_deleted:
    raise RuntimeError('Thread already deleted; cannot read messages')
msgs = [m async for m in thread.get_messages()]

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Calling thread.get_messages() after thread.delete() has been called on the same AgentThread instance; reusing a thread handle whose lifecycle has ended.

Common situations: Teardown then a delayed/raced read; holding a thread reference across a delete boundary; cleanup logic that deletes then a finally-block tries to log messages.

Related errors


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