github/copilot-sdk · error · InvalidOperationException
Client is not started. Call StartAsync first.
Error message
Client is not started. Call StartAsync first.
What it means
CopilotClient.Rpc throws InvalidOperationException because the internal _serverRpc is null — StartAsync was never called (or has not completed) before the property was accessed. The docs require calling StartAsync before using Rpc.
Solutions
- Call await client.StartAsync() before reading Rpc
- Ensure StartAsync completed successfully (await its task and check for exceptions)
- If start failed, fix the underlying startup error and retry StartAsync
Example fix
// before var client = new CopilotClient(options); var rpc = client.Rpc; // after var client = new CopilotClient(options); await client.StartAsync(); var rpc = client.Rpc;
Defensive patterns
Strategy: try-catch
Validate before calling
// _serverRpc is private; enforce start-before-use at the call site
if (!started) throw new InvalidOperationException("Call StartAsync first"); Try / catch
try { var rpc = client.Rpc; } catch (InvalidOperationException ex) when (ex.Message.Contains("StartAsync")) { await client.StartAsync(); var rpc = client.Rpc; } Prevention
- Always await StartAsync before any member access
- Wrap client creation+start in a single async factory method
- Avoid exposing the raw client; expose it only after startup completes
When it happens
Trigger: Accessing client.Rpc immediately after constructing CopilotClient, or before awaiting StartAsync, or after StartAsync failed and left the channel unassigned.
Common situations: Forgetting to await the StartAsync task; firing-and-forgetting StartAsync; using the client in a constructor where async startup hasn't finished; start failure swallowed upstream.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot log after the factory run has settled
- Exception of type 'System.ObjectDisposedException' was…
- Runtime process not started
- Unknown session
- CLI process not started
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/a2492514d4076707.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/Client.cs:112
/// <summary>
/// Client-global RPC handlers (e.g. the LLM inference provider adapter),
/// built once at construction and registered on every connection.
/// </summary>
private readonly ClientGlobalApiHandlers? _clientGlobalApis;
private sealed record LifecycleSubscription(Type EventType, Action<SessionLifecycleEvent> Handler);
/// <summary>
/// Gets the typed RPC client for server-scoped methods (no session required).
/// </summary>
/// <remarks>
/// The client must be started before accessing this property. Call <see cref="StartAsync"/> before use.
/// </remarks>
/// <exception cref="ObjectDisposedException">Thrown if the client has been disposed.</exception>
/// <exception cref="InvalidOperationException">Thrown if the client is not started.</exception>
public ServerRpc Rpc => _disposed
? throw new ObjectDisposedException(nameof(CopilotClient))
: _serverRpc ?? throw new InvalidOperationException("Client is not started. Call StartAsync first.");
/// <summary>
/// Gets the actual TCP port the runtime is listening on, if using TCP transport.
/// </summary>
public int? RuntimePort => _actualPort;
/// <summary>
/// Creates a new instance of <see cref="CopilotClient"/>.
/// </summary>
/// <param name="options">Options for creating the client. If null, default options are used.</param>
/// <example>
/// <code>
/// // Default options - spawns the bundled runtime using stdio
/// var client = new CopilotClient();
///
/// // Connect to an existing runtime
/// var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri("localhost:3000") });
///View on GitHub (pinned to cd8cf15dc3)