{"record":{"id":"5459f8d7bedb8fe3","repo":"microsoft/semantic-kernel","slug":"this-thread-has-been-deleted-and-cannot-be-used-an-5459f8","errorCode":null,"errorMessage":"This thread has been deleted and cannot be used anymore.","messagePattern":"This thread has been deleted and cannot be used anymore\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Agents/OpenAI/OpenAIAssistantAgentThread.cs","lineNumber":187,"sourceCode":"            {\n                throw new AgentThreadOperationException(ErrorMessage, ex);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Asynchronously retrieves all messages in the thread.\n    /// </summary>\n    /// <param name=\"sortOrder\">The order to return messages in.</param>\n    /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> to monitor for cancellation requests. The default is <see cref=\"CancellationToken.None\"/>.</param>\n    /// <returns>The messages in the thread.</returns>\n    /// <exception cref=\"InvalidOperationException\">The thread has been deleted.</exception>\n    [Experimental(\"SKEXP0110\")]\n    public async IAsyncEnumerable<ChatMessageContent> GetMessagesAsync(MessageCollectionOrder? sortOrder = default, [EnumeratorCancellation] CancellationToken cancellationToken = default)\n    {\n        if (this.IsDeleted)\n        {\n            throw new InvalidOperationException(\"This thread has been deleted and cannot be used anymore.\");\n        }\n\n        if (this.Id is null)\n        {\n            await this.CreateAsync(cancellationToken).ConfigureAwait(false);\n        }\n\n        await foreach (var message in AssistantThreadActions.GetMessagesAsync(this._client, this.Id!, sortOrder, cancellationToken).ConfigureAwait(false))\n        {\n            yield return message;\n        }\n    }\n}\n","sourceCodeStart":169,"sourceCodeEnd":201,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Agents/OpenAI/OpenAIAssistantAgentThread.cs#L169-L201","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do not call GetMessagesAsync after DeleteAsync — read messages first, then delete.","Guard with 'if (!thread.IsDeleted)' before enumerating.","Create a fresh OpenAIAssistantAgentThread for a new conversation instead of reusing a deleted one."],"exampleFix":"// before\nawait thread.DeleteAsync();\nvar msgs = await thread.GetMessagesAsync().ToListAsync(); // throws\n\n// after\nvar msgs = await thread.GetMessagesAsync().ToListAsync();\nawait thread.DeleteAsync();","handlingStrategy":"validation","validationCode":"if (!thread.IsDeleted)\n{\n    var messages = await thread.GetMessagesAsync().ToListAsync();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Read messages before calling DeleteAsync.","Treat IsDeleted as terminal: never reuse a deleted thread.","Centralize thread lifecycle so background tasks cannot outlive deletion."],"tags":["thread","lifecycle","validation","agents"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}