github/copilot-sdk · error · InvalidOperationException

session.create returned sessionId

Error message

session.create returned sessionId {response.SessionId} but the caller requested {localSessionId}.

What it means

This InvalidOperationException is thrown by CopilotClient when the CLI's session.create RPC response returns a sessionId that does not exactly match the sessionId the caller explicitly requested for the new session. The library treats a mismatched session ID as a protocol violation, since the caller supplied localSessionId and the server must honor it. It guards callers from silently using a session under the wrong ID.

Solutions

  1. Remove the explicit localSessionId argument and let the CLI generate the session ID, then use response.SessionId
  2. Upgrade (or align) the Copilot CLI/server version so session.create honors caller-requested session IDs
  3. Compare versions: if you pinned a session ID for resume semantics, use the session resume/reconnect API instead of session.create
  4. Check for multiple connections/clients sharing the same RPC channel that could interleave responses

Example fix

// before
var session = await client.CreateSessionAsync(new SessionConfig { SessionId = myId });
// after
var session = await client.CreateSessionAsync(new SessionConfig()); // let CLI assign; use session.Id afterwards
Defensive patterns

Strategy: validation

Validate before calling

if (config.SessionId is not null && string.IsNullOrWhiteSpace(config.SessionId)) throw new ArgumentException("SessionId must be null or a non-empty exact id");

Type guard

static bool IsValidRequestedSessionId(SessionConfig c) => c.SessionId is null || c.SessionId.Length > 0;

Try / catch

try { await client.CreateSessionAsync(config); }
catch (InvalidOperationException ex) when (ex.Message.Contains("session.create returned sessionId"))
{ logger.LogError(ex, "CLI ignored requested session id; falling back to server id"); /* recreate without localSessionId */ }

Prevention

When it happens

Trigger: Calling session creation (e.g. CreateSessionAsync / StartSessionAsync) with a non-null localSessionId while the Copilot CLI server responds with a different SessionId; typically a server/CLI version that does not honor client-supplied session IDs, or a bug/misconfiguration in the connection.

Common situations: Running an older or newer Copilot CLI whose session.create implementation ignores or regenerates caller-supplied session IDs; two clients racing to create sessions with the same ID; a misrouted/proxied RPC connection replying with another session's response.

Related errors


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

Appendix: source

Thrown at dotnet/src/Client.cs:1347

                        "CopilotClient.CreateSessionAsync");
                }
            };

            var response = await InvokeRpcAsync<CreateSessionResponse>(
                connection.Rpc, "session.create", [request], null, cancellationToken, onResponseInline);
            LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,
                "CopilotClient.CreateSessionAsync session creation request completed successfully. Elapsed={Elapsed}, SessionId={SessionId}",
                rpcTimestamp,
                response.SessionId);

            if (session is null)
            {
                throw new InvalidOperationException("session.create response did not include a sessionId.");
            }

            if (localSessionId != null && !string.Equals(localSessionId, response.SessionId, StringComparison.Ordinal))
            {
                throw new InvalidOperationException(
                    $"session.create returned sessionId {response.SessionId} but the caller requested {localSessionId}.");
            }

            if (config.OnMcpAuthRequest is not null)
            {
                await session.Rpc.EventLog.RegisterInterestAsync("mcp.oauth_required", cancellationToken);
            }

            session.WorkspacePath = response.WorkspacePath;
            session.SetCapabilities(response.Capabilities);
            session.SetOpenCanvases(response.OpenCanvases);

            await UpdateSessionOptionsForModeAsync(session, config, cancellationToken).ConfigureAwait(false);
            if (registrationId is not null)
            {
                session.SetGitHubTokenProviderRegistration(registrationId);
                registrationTransferred = true;
            }

View on GitHub (pinned to cd8cf15dc3)