github/copilot-sdk · error · InvalidOperationException

{response.Error ?? "Failed to set foreground session"}

Error message

{response.Error ?? "Failed to set foreground session"}

What it means

Thrown when the session.setForeground RPC returns Success=false; the server's response.Error text is used if present, otherwise the generic 'Failed to set foreground session' message. Foreground designation tells the CLI which session receives user input/events, so a false response means the operation was rejected.

Solutions

  1. Verify the sessionId is a live session created via this client and not yet deleted
  2. Wrap the call so you can fall back or no-op when the session already ended
  3. Call SetForegroundSessionAsync immediately after session creation, before any disposal
  4. Update the Copilot CLI if the server consistently rejects valid sessions

Example fix

// before
await client.SetForegroundSessionAsync(sessionId);
// after
if (!session.IsCompleted)
{
    await client.SetForegroundSessionAsync(sessionId);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!activeSessions.Contains(sessionId)) throw new InvalidOperationException("cannot set foreground on unknown/ended session");

Try / catch

try { await client.SetForegroundSessionAsync(sessionId); }
catch (InvalidOperationException ex) when (ex.Message.Contains("foreground"))
{ logger.LogWarning("foreground switch rejected: {Reason}", ex.Message); }

Prevention

When it happens

Trigger: Calling SetForegroundSessionAsync with a sessionId the server does not recognize, a session that already ended, or when the server refuses the foreground switch for lifecycle reasons.

Common situations: Setting foreground for a session after it completed/errored; using a session ID from another connection; racing session disposal with the foreground call.

Related errors


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

Appendix: source

Thrown at dotnet/src/Client.cs:1874

    /// <param name="cancellationToken">A token to cancel the operation.</param>
    /// <exception cref="InvalidOperationException">Thrown if the operation fails.</exception>
    /// <example>
    /// <code>
    /// await client.SetForegroundSessionIdAsync("session-123");
    /// </code>
    /// </example>
    public async Task SetForegroundSessionIdAsync(string sessionId, CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(sessionId);

        var connection = await EnsureConnectedAsync(cancellationToken);

        var response = await InvokeRpcAsync<SetForegroundSessionResponse>(
            connection.Rpc, "session.setForeground", [new SetForegroundSessionRequest(sessionId)], cancellationToken);

        if (!response.Success)
        {
            throw new InvalidOperationException(response.Error ?? "Failed to set foreground session");
        }
    }

    /// <summary>
    /// Subscribes to session lifecycle events of a specific kind.
    /// </summary>
    /// <typeparam name="T">
    /// The lifecycle event type to listen for. Pass a derived type such as
    /// <see cref="SessionCreatedEvent"/> to filter by kind, or
    /// <see cref="SessionLifecycleEvent"/> to receive every lifecycle event.
    /// </typeparam>
    /// <param name="handler">A callback invoked when a matching lifecycle event arrives.</param>
    /// <returns>An <see cref="IDisposable"/> that, when disposed, unsubscribes the handler.</returns>
    /// <example>
    /// <code>
    /// using var sub = client.OnLifecycle&lt;SessionForegroundEvent&gt;(evt =&gt;
    /// {
    ///     Console.WriteLine($"Session {evt.SessionId} is now in foreground");

View on GitHub (pinned to cd8cf15dc3)