microsoft/semantic-kernel · error · InvalidOperationException

This thread has been deleted and cannot be used anymore.

Error message

This thread has been deleted and cannot be used anymore.

What it means

Thrown by GetMessagesAsync when the thread's IsDeleted flag is true. IsDeleted is set to true by the base AgentThread.DeleteAsync, and once set the thread is permanently unusable. This is a lifecycle guard, not a service error.

Source

Thrown at dotnet/src/Agents/OpenAI/OpenAIAssistantAgentThread.cs:187

            {
                throw new AgentThreadOperationException(ErrorMessage, ex);
            }
        }
    }

    /// <summary>
    /// Asynchronously retrieves all messages in the thread.
    /// </summary>
    /// <param name="sortOrder">The order to return messages in.</param>
    /// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
    /// <returns>The messages in the thread.</returns>
    /// <exception cref="InvalidOperationException">The thread has been deleted.</exception>
    [Experimental("SKEXP0110")]
    public async IAsyncEnumerable<ChatMessageContent> GetMessagesAsync(MessageCollectionOrder? sortOrder = default, [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        if (this.IsDeleted)
        {
            throw new InvalidOperationException("This thread has been deleted and cannot be used anymore.");
        }

        if (this.Id is null)
        {
            await this.CreateAsync(cancellationToken).ConfigureAwait(false);
        }

        await foreach (var message in AssistantThreadActions.GetMessagesAsync(this._client, this.Id!, sortOrder, cancellationToken).ConfigureAwait(false))
        {
            yield return message;
        }
    }
}

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Do not call GetMessagesAsync after DeleteAsync — read messages first, then delete.
  2. Guard with 'if (!thread.IsDeleted)' before enumerating.
  3. Create a fresh OpenAIAssistantAgentThread for a new conversation instead of reusing a deleted one.

Example fix

// before
await thread.DeleteAsync();
var msgs = await thread.GetMessagesAsync().ToListAsync(); // throws

// after
var msgs = await thread.GetMessagesAsync().ToListAsync();
await thread.DeleteAsync();
Defensive patterns

Strategy: validation

Validate before calling

if (!thread.IsDeleted)
{
    var messages = await thread.GetMessagesAsync().ToListAsync();
}

Prevention

When it happens

Trigger: await thread.DeleteAsync(); ... await thread.GetMessagesAsync(...); — any read of messages after the thread has been deleted. Also reachable if a prior DeleteAsync succeeded but the caller did not refresh its local reference and kept the same instance.

Common situations: Application flow deletes a conversation thread on session end but a background task (e.g. a logging/middleware pipeline) still enumerates messages; reuse of a thread object across requests after one request deleted it.

Related errors


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