microsoft/semantic-kernel · error · ValueError
The thread has been deleted.
Error message
The thread has been deleted.
What it means
Raised as a plain ValueError by AssistantAgentThread.get_messages() after the thread's _delete() already ran. The thread object tracks an internal _is_deleted flag; once true, the OpenAI thread id is gone server-side so listing messages has no valid target. Calling get_messages on a deleted thread is a state-machine violation, not a network failure.
Source
Thrown at python/semantic_kernel/agents/open_ai/openai_assistant_agent.py:219
if (
not new_message.metadata
or "thread_id" not in new_message.metadata
or new_message.metadata["thread_id"] != self._id
):
assert self._id is not None # nosec
await AssistantThreadActions.create_message(self._client, self._id, new_message)
async def get_messages(self, sort_order: Literal["asc", "desc"] | None = None) -> AsyncIterable[ChatMessageContent]:
"""Get the messages in the thread.
Args:
sort_order: The order to sort the messages in. Either "asc" or "desc".
Yields:
An AsyncIterable of ChatMessageContent of the messages in the thread.
"""
if self._is_deleted:
raise ValueError("The thread has been deleted.")
if self._id is None:
await self.create()
assert self.id is not None # nosec
async for message in AssistantThreadActions.get_messages(self._client, self.id, sort_order=sort_order):
yield message
@release_candidate
@register_agent_type("openai_assistant")
class OpenAIAssistantAgent(DeclarativeSpecMixin, Agent):
"""OpenAI Assistant Agent class.
Provides the ability to interact with OpenAI Assistants.
"""
# region Agent Initialization
client: AsyncOpenAIView on GitHub (pinned to c028a0c7dc)
Solutions
- Do not call get_messages() after delete(); create a fresh AssistantAgentThread for a new conversation.
- Guard the call with the thread's lifecycle state or recreate the thread before reading.
- Ensure no concurrent coroutines delete the thread while another reads it.
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 getattr(thread, '_is_deleted', False):
raise RuntimeError('thread already deleted; create a new one')
messages = [m async for m in thread.get_messages()] Type guard
def thread_is_alive(thread: AssistantAgentThread) -> bool:
return not getattr(thread, '_is_deleted', False) Try / catch
try:
msgs = [m async for m in thread.get_messages()]
except ValueError as e:
if 'deleted' in str(e):
thread = AssistantAgentThread(client=client)
else:
raise Prevention
- Never read messages after delete(); order teardown last.
- Replace the thread reference on reset instead of mutating state.
- Track thread lifecycle in your own state machine.
When it happens
Trigger: You call await thread.delete() (or _delete()) and then later call await thread.get_messages(...) on the same AssistantAgentThread instance. Also occurs if delete() ran as part of chat teardown and a follow-up component still holds the old thread reference and queries messages.
Common situations: Reusing a thread variable across conversation turns in a long-lived agent; cleanup hooks that delete the thread while a parallel coroutine is still reading history; agent-chat finishers that delete then log messages.
Related errors
- Cannot create a new thread, since the current thread has bee
- Cannot delete the thread, since it has not been created.
- Failed to create OpenAI settings.
- The OpenAI API key is required.
- The OpenAI model ID is required.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/bb5c53f88ea66af2.
Report an issue: GitHub.