microsoft/semantic-kernel · warning · AgentThreadOperationException

The thread cannot be deleted because it has not been created

Error message

The thread cannot be deleted because it has not been created yet.

What it means

Raised by AzureAIAgentThread._delete when self._id is None, meaning the thread was constructed without an existing thread_id and _create was never successfully called. You cannot delete a thread that has no server-side identity. Surfaced as AgentThreadOperationException.

Source

Thrown at python/semantic_kernel/agents/azure_ai/azure_ai_agent.py:311

    async def _create(self) -> str:
        """Starts the thread and returns its ID."""
        try:
            response = await self._client.agents.threads.create(
                messages=self._messages,
                metadata=self._metadata,
                tool_resources=self._tool_resources,
            )
        except Exception as ex:
            raise AgentThreadOperationException(
                "The thread could not be created due to an error response from the service."
            ) from ex
        return response.id

    @override
    async def _delete(self) -> None:
        """Ends the current thread."""
        if self._id is None:
            raise AgentThreadOperationException("The thread cannot be deleted because it has not been created yet.")
        try:
            await self._client.agents.threads.delete(self._id)
        except Exception as ex:
            raise AgentThreadOperationException(
                "The thread could not be deleted due to an error response from the service."
            ) from ex

    @override
    async def _on_new_message(self, new_message: str | ChatMessageContent) -> None:
        """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
        ):

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Guard the delete: only call delete() if thread.id is not None (i.e. it was created or supplied).
  2. Ensure create() succeeded before scheduling deletion; check the return of create().
  3. In cleanup/finally blocks, check thread._id or thread.id before invoking delete().

Example fix

// before
thread = AzureAIAgentThread(client=client)
await thread.delete()  // _id is None
// after
thread = AzureAIAgentThread(client=client)
await thread.create()   // assigns _id
if thread.id is not None:
    await thread.delete()
Defensive patterns

Strategy: validation

Validate before calling

async def safe_delete(thread):
    if getattr(thread, '_id', None) is None:
        return  # nothing to delete
    await thread.delete()

Type guard

def thread_has_id(thread) -> bool:
    return getattr(thread, '_id', None) is not None

Try / catch

try:
    await thread.delete()
except AgentThreadOperationException as e:
    if 'has not been created' in str(e):
        return  # benign: nothing to delete
    raise

Prevention

When it happens

Trigger: Constructing AzureAIAgentThread(client=c) with no thread_id, then immediately calling delete() without first calling create(); calling delete after a failed create() that left _id as None; double lifecycle management where one path deletes before creation.

Common situations: Error-handling/cleanup code that unconditionally calls delete in a finally block before the thread was created; race where create() threw (see error 745) but cleanup proceeds to delete(); confusing a locally-constructed thread with a remote one.

Related errors


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