microsoft/semantic-kernel · error · InvalidOperationException

This thread cannot be deleted, since it has not been created

Error message

This thread cannot be deleted, since it has not been created.

What it means

Thrown by DeleteInternalAsync on OpenAIResponseAgentThread when ResponseId is null. Unlike assistant threads, a Response thread's identity is the id of the first response, which only exists after a message has been sent. Deleting before any response was created has nothing to delete, so the library throws InvalidOperationException.

Source

Thrown at dotnet/src/Agents/OpenAI/OpenAIResponseAgentThread.cs:75

        {
            throw new InvalidOperationException("This thread has been deleted and cannot be recreated.");
        }

        // Id will not be available until after a message is sent
        return Task.FromResult<string?>(null);
    }

    /// <inheritdoc />
    protected override async Task DeleteInternalAsync(CancellationToken cancellationToken = default)
    {
        if (this._isDeleted)
        {
            return;
        }

        if (this.ResponseId is null)
        {
            throw new InvalidOperationException("This thread cannot be deleted, since it has not been created.");
        }

        try
        {
            await this._client.DeleteResponseAsync(this.ResponseId, cancellationToken).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            throw new AgentThreadOperationException("The thread could not be deleted due to an error response from the service.", ex);
        }

        this._isDeleted = true;
    }

    /// <inheritdoc/>
    protected override Task OnNewMessageInternalAsync(ChatMessageContent newMessage, CancellationToken cancellationToken = default)
    {
        if (this._isDeleted)

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Only delete after a response exists — check that thread.Id (the ResponseId) is non-null before calling DeleteAsync.
  2. Guard cleanup: if (thread.Id is not null) await thread.DeleteAsync();
  3. For early-abort flows, simply drop the reference instead of deleting.

Example fix

// before
var thread = new OpenAIResponseAgentThread(client);
// user cancels before any message...
await thread.DeleteAsync(); // throws — nothing to delete

// after
if (!string.IsNullOrEmpty(thread.Id))
{
    await thread.DeleteAsync();
}
Defensive patterns

Strategy: validation

Validate before calling

if (!string.IsNullOrEmpty(thread.Id))
{
    await thread.DeleteAsync();
}

Prevention

When it happens

Trigger: new OpenAIResponseAgentThread(client); then immediately await thread.DeleteAsync(); without ever invoking the agent (so no ResponseId was ever assigned).

Common situations: Cleanup/dispose logic that unconditionally deletes a thread, including the never-used case; aborting a conversation before the first message round-trip.

Related errors


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