github/copilot-sdk · error · IllegalStateException
Client not connected; call start() first
Error message
Client not connected; call start() first
What it means
getRpc() returns the ServerRpc handle only after start() has successfully established a connection. If the connection future is null, still pending, or completed exceptionally, the client has no RPC channel and IllegalStateException is thrown.
Solutions
- Call start() and await its completion before getRpc(): client.start().join() (or thenAccept)
- Check the exception cause of the failed connection future (start().exceptionally) — likely server launch failure
- Gate all RPC usage behind a readiness flag set after start() completes
Example fix
// before ServerRpc rpc = client.getRpc(); // after client.start().join(); ServerRpc rpc = client.getRpc();
Defensive patterns
Strategy: validation
Validate before calling
if (client.getConnectionFuture() == null || !client.getConnectionFuture().isDone()) {
client.start().join(); // or await readiness signal
} Try / catch
try {
ServerRpc rpc = client.getRpc();
} catch (IllegalStateException e) {
if (e.getMessage().contains("not connected")) {
client.start().join();
}
} Prevention
- Always call start() and await completion in initialization code
- Gate RPC access behind an application readiness flag
- Diagnose start() failures early instead of letting later getRpc() calls surface them
When it happens
Trigger: Calling client.getRpc() before start(), while start()'s connection handshake is still in flight, or after connection failed (future completed exceptionally).
Common situations: Forgetting start() in new integration code; racing getRpc() immediately after start() without awaiting the returned future; server binary failed to launch so the connection never completes.
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
- Client is not connected. Call start() first.
- Client not connected. Call start() first.
- Session is not connected — RPC client is unavailable
- LLM inference response used after RPC connection closed
- Unknown session
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/6d896f0b7840623a.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/CopilotClient.java:1456
* Provides strongly-typed access to all server-level API namespaces such as
* {@code models}, {@code tools}, {@code account}, and {@code mcp}.
* <p>
* Example usage:
*
* <pre>{@code
* client.start().get();
* var models = client.getRpc().models.list().get();
* }</pre>
*
* @return the server-level typed RPC client
* @throws IllegalStateException
* if the client is not connected; call {@link #start()} first
* @since 1.0.0
*/
public ServerRpc getRpc() {
CompletableFuture<Connection> future = connectionFuture;
if (future == null || !future.isDone() || future.isCompletedExceptionally()) {
throw new IllegalStateException("Client not connected; call start() first");
}
return future.join().serverRpc();
}
/**
* Pings the server to check connectivity.
* <p>
* This can be used to verify that the server is responsive and to check the
* protocol version.
*
* @param message
* an optional message to echo back
* @return a future that resolves with the ping response
* @see PingResponse
*/
public CompletableFuture<PingResponse> ping(String message) {
return ensureConnected().thenCompose(connection -> connection.rpc.invoke("ping",
Map.of("message", message != null ? message : ""), PingResponse.class));View on GitHub (pinned to cd8cf15dc3)