github/copilot-sdk · error · InvalidOperationException

Failed to delete session

Error message

Failed to delete session {sessionId}: {response.Error}

What it means

Thrown when the session.delete RPC completes but the CLI responds with Success=false, with response.Error carrying the server-side reason. The library surfaces that server message verbatim so the developer knows why deletion failed. The local session cache is only cleaned up when deletion succeeds.

Solutions

  1. Read response.Error embedded in the message for the server-side cause and fix accordingly (e.g. unknown session = already deleted)
  2. Guard against double deletion: track whether the session was already deleted before calling DeleteSessionAsync again
  3. Verify the sessionId matches one created on the same connection/client instance
  4. If the session is already gone, treat this as idempotent: catch InvalidOperationException and continue cleanup

Example fix

// before
await client.DeleteSessionAsync(sessionId);
// after
try { await client.DeleteSessionAsync(sessionId); }
catch (InvalidOperationException) { /* already deleted on server; ignore */ }
Defensive patterns

Strategy: try-catch

Validate before calling

if (_deletedSessions.Contains(sessionId)) return; // skip duplicate delete

Try / catch

try { await client.DeleteSessionAsync(sessionId); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Failed to delete session"))
{ logger.LogWarning(ex, "session delete rejected (possibly already gone)"); }

Prevention

When it happens

Trigger: Calling DeleteSessionAsync (or disposing a session that deletes on close) for a sessionId the server rejects: already deleted, unknown to the server, or the server reports an internal error deleting it.

Common situations: Double-dispose / deleting the same session twice; deleting a session created on a different connection; CLI crash or restart that invalidated the session; server-side permission or lifecycle errors.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/020c479f0eb1ba5a. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/src/Client.cs:1753

    /// irreversible. The session cannot be resumed after deletion.
    /// </remarks>
    /// <example>
    /// <code>
    /// await client.DeleteSessionAsync("session-123");
    /// </code>
    /// </example>
    public async Task DeleteSessionAsync(string sessionId, CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(sessionId);

        var connection = await EnsureConnectedAsync(cancellationToken);

        var response = await InvokeRpcAsync<DeleteSessionResponse>(
            connection.Rpc, "session.delete", [new DeleteSessionRequest(sessionId)], cancellationToken);

        if (!response.Success)
        {
            throw new InvalidOperationException($"Failed to delete session {sessionId}: {response.Error}");
        }

        if (_sessions.TryRemove(sessionId, out var session))
        {
            session.ReleaseGitHubTokenProviderRegistration();
        }
    }

    /// <summary>
    /// Lists all sessions known to the Copilot server.
    /// </summary>
    /// <param name="filter">Optional filter to narrow down the session list by cwd, git root, repository, or branch.</param>
    /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the operation.</param>
    /// <returns>A task that resolves with a list of <see cref="SessionMetadata"/> for all available sessions.</returns>
    /// <exception cref="InvalidOperationException">Thrown when the client is not connected.</exception>
    /// <example>
    /// <code>
    /// var sessions = await client.ListSessionsAsync();

View on GitHub (pinned to cd8cf15dc3)