{"record":{"id":"d53b6b9f606f9af0","repo":"microsoft/semantic-kernel","slug":"this-thread-cannot-be-deleted-since-it-has-not-be","errorCode":null,"errorMessage":"This thread cannot be deleted, since it has not been created.","messagePattern":"This thread cannot be deleted, since it has not been created\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Agents/Abstractions/AgentThread.cs","lineNumber":116,"sourceCode":"#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n    }\n\n    /// <summary>\n    /// Deletes the current thread.\n    /// </summary>\n    /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> to monitor for cancellation requests. The default is <see cref=\"CancellationToken.None\"/>.</param>\n    /// <returns>A task that completes when the thread has been deleted.</returns>\n    /// <exception cref=\"InvalidOperationException\">The thread was never created.</exception>\n    public virtual async Task DeleteAsync(CancellationToken cancellationToken = default)\n    {\n        if (this.IsDeleted)\n        {\n            return;\n        }\n\n        if (this.Id is null)\n        {\n            throw new InvalidOperationException(\"This thread cannot be deleted, since it has not been created.\");\n        }\n\n#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n        await this.AIContextProviders.ConversationDeletingAsync(this.Id, cancellationToken).ConfigureAwait(false);\n#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.\n\n        await this.DeleteInternalAsync(cancellationToken).ConfigureAwait(false);\n\n        this.IsDeleted = true;\n    }\n\n    /// <summary>\n    /// This method is called when a new message has been contributed to the chat by any participant.\n    /// </summary>\n    /// <remarks>\n    /// Inheritors can use this method to update their context based on the new message.\n    /// </remarks>\n    /// <param name=\"newMessage\">The new message.</param>","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Agents/Abstractions/AgentThread.cs#L98-L134","documentation":"Thrown by AgentThread.DeleteAsync when the thread was never created on the backend (this.Id is null). The base AgentThread lifecycle requires that CreateAsync (or a resume-from-existing-id constructor) has run first, setting the Id property, before deletion is meaningful. The method short-circuits with a no-op if already deleted, but rejects deletion of a never-started thread.","triggerScenarios":"Calling thread.DeleteAsync() on a fresh AgentThread instance whose CreateAsync was never invoked and that was not constructed with an existing thread Id. This can also happen if the first message that would trigger lazy creation (via OnNewMessageAsync) was never sent.","commonSituations":"Developer creates an AzureAIAgentThread(client) (no id overload), then immediately calls DeleteAsync without ever invoking the agent or calling CreateAsync. Also occurs in cleanup/disposal paths that run even when the main workflow threw before thread creation.","solutions":["Check thread.Id is not null before calling DeleteAsync, or call CreateAsync first.","Guard with: if (!thread.IsDeleted && thread.Id is not null) await thread.DeleteAsync(ct);","Restructure cleanup logic so DeleteAsync only runs in a finally block when creation has already succeeded."],"exampleFix":"// before\nvar thread = new AzureAIAgentThread(client);\nawait thread.DeleteAsync(ct); // throws\n\n// after\nvar thread = new AzureAIAgentThread(client);\nif (thread.Id is not null && !thread.IsDeleted)\n{\n    await thread.DeleteAsync(ct);\n}","handlingStrategy":"validation","validationCode":"if (thread is { IsDeleted: false, Id: null })\n{\n    // Thread was never created; skip or create first\n    return; // or await thread.CreateAsync(ct);\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    await thread.DeleteAsync(ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"has not been created\"))\n{\n    // Thread was never created; nothing to clean up\n    _logger.LogDebug(\"Thread was never created, skipping deletion.\");\n}","preventionTips":["Track thread creation state in a wrapper or local variable.","Only call DeleteAsync in a finally block that runs after successful creation.","Use the two-argument constructor AzureAIAgentThread(client, existingId) when resuming to set Id immediately."],"tags":["agent-thread","lifecycle","invalidoperation"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}