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
- Only delete after a response exists — check that thread.Id (the ResponseId) is non-null before calling DeleteAsync.
- Guard cleanup: if (thread.Id is not null) await thread.DeleteAsync();
- 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
- Only delete a Response thread after it has an Id (a response was created).
- Make cleanup conditional on Id being present.
- For early aborts, drop the reference instead of deleting.
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
- This thread has been deleted and cannot be recreated.
- This thread has been deleted and cannot be used anymore.
- This thread has been deleted and cannot be used anymore.
- The thread could not be deleted due to an error response fro
- Thread has been deleted; call `create()` to recreate it.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/19e4f922e3241df2.
Report an issue: GitHub.