{"record":{"id":"a2492514d4076707","repo":"github/copilot-sdk","slug":"client-is-not-started-call-startasync-first","errorCode":null,"errorMessage":"Client is not started. Call StartAsync first.","messagePattern":"Client is not started\\. Call StartAsync first\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Client.cs","lineNumber":112,"sourceCode":"    /// <summary>\n    /// Client-global RPC handlers (e.g. the LLM inference provider adapter),\n    /// built once at construction and registered on every connection.\n    /// </summary>\n    private readonly ClientGlobalApiHandlers? _clientGlobalApis;\n\n    private sealed record LifecycleSubscription(Type EventType, Action<SessionLifecycleEvent> Handler);\n\n    /// <summary>\n    /// Gets the typed RPC client for server-scoped methods (no session required).\n    /// </summary>\n    /// <remarks>\n    /// The client must be started before accessing this property. Call <see cref=\"StartAsync\"/> before use.\n    /// </remarks>\n    /// <exception cref=\"ObjectDisposedException\">Thrown if the client has been disposed.</exception>\n    /// <exception cref=\"InvalidOperationException\">Thrown if the client is not started.</exception>\n    public ServerRpc Rpc => _disposed\n        ? throw new ObjectDisposedException(nameof(CopilotClient))\n        : _serverRpc ?? throw new InvalidOperationException(\"Client is not started. Call StartAsync first.\");\n\n    /// <summary>\n    /// Gets the actual TCP port the runtime is listening on, if using TCP transport.\n    /// </summary>\n    public int? RuntimePort => _actualPort;\n\n    /// <summary>\n    /// Creates a new instance of <see cref=\"CopilotClient\"/>.\n    /// </summary>\n    /// <param name=\"options\">Options for creating the client. If null, default options are used.</param>\n    /// <example>\n    /// <code>\n    /// // Default options - spawns the bundled runtime using stdio\n    /// var client = new CopilotClient();\n    ///\n    /// // Connect to an existing runtime\n    /// var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(\"localhost:3000\") });\n    ///","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/Client.cs#L94-L130","documentation":"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.","triggerScenarios":"Accessing client.Rpc immediately after constructing CopilotClient, or before awaiting StartAsync, or after StartAsync failed and left the channel unassigned.","commonSituations":"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.","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"],"exampleFix":"// before\nvar client = new CopilotClient(options);\nvar rpc = client.Rpc;\n// after\nvar client = new CopilotClient(options);\nawait client.StartAsync();\nvar rpc = client.Rpc;","handlingStrategy":"try-catch","validationCode":"// _serverRpc is private; enforce start-before-use at the call site\nif (!started) throw new InvalidOperationException(\"Call StartAsync first\");","typeGuard":null,"tryCatchPattern":"try { var rpc = client.Rpc; } catch (InvalidOperationException ex) when (ex.Message.Contains(\"StartAsync\")) { await client.StartAsync(); var rpc = client.Rpc; }","preventionTips":["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"],"tags":["dotnet","async","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}