github/copilot-sdk · error · IllegalArgumentException
CopilotClient was created with Mode = EMPTY but neither…
Error message
CopilotClient was created with Mode = EMPTY but neither CopilotHome nor CliUrl was set. Empty mode requires an explicit per-session persistence location.
What it means
CopilotClientMode.EMPTY gives the client no default persistence location, so it requires an explicit per-session persistence location: either CopilotHome (a directory) or CliUrl (an external server that manages its own home). If neither is set, the constructor throws IllegalArgumentException rather than silently picking a shared location that could corrupt session state.
Solutions
- Set a unique copilotHome directory for the session
- Or set cliUrl to point at an external server managing persistence
- Or use a different CopilotClientMode if per-session isolation is not needed
Example fix
// before
options.setMode(CopilotClientMode.EMPTY);
// after
options.setMode(CopilotClientMode.EMPTY);
options.setCopilotHome("/tmp/copilot-session-" + sessionId); Defensive patterns
Strategy: validation
Validate before calling
if (mode == CopilotClientMode.EMPTY && isBlank(home) && isBlank(cliUrl)) throw new IllegalArgumentException("EMPTY mode needs copilotHome or cliUrl"); Try / catch
try { new CopilotClient(options); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Mode = EMPTY")) { options.setCopilotHome(...); } else throw e; } Prevention
- Always pair EMPTY mode with a per-session copilotHome
- Centralize client construction so the pairing cannot be forgotten
When it happens
Trigger: new CopilotClient(...) with options.setMode(CopilotClientMode.EMPTY) and both getCopilotHome() null/empty and getCliUrl() null/empty.
Common situations: Switching a client to EMPTY mode for isolation but forgetting to set a per-session CopilotHome; building options dynamically where both fields stayed null.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- CliUrl is mutually exclusive with CliPath
- GitHubToken and UseLoggedInUser cannot be used with CliUrl…
- TcpConnectionToken must be a non-empty string
- TcpConnectionToken cannot be used with UseStdio = true
- Invalid value ' '. Expected 'inprocess', 'stdio', or unset.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/70b9e6c24a6f9566.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/CopilotClient.java:215
throw new IllegalArgumentException("TcpConnectionToken cannot be used with UseStdio = true");
}
}
// Compute effective connection token: use provided, or auto-generate for
// SDK-spawned TCP mode, or null for stdio/external server
boolean sdkSpawnsCli = !this.options.isUseStdio()
&& (this.options.getCliUrl() == null || this.options.getCliUrl().isEmpty());
this.effectiveConnectionToken = this.options.getTcpConnectionToken() != null
? this.options.getTcpConnectionToken()
: (sdkSpawnsCli ? java.util.UUID.randomUUID().toString() : null);
// Empty mode: validate at construction time that the app supplied a
// per-session persistence location.
if (this.options.getMode() == CopilotClientMode.EMPTY) {
boolean hasPersistence = (this.options.getCopilotHome() != null && !this.options.getCopilotHome().isEmpty())
|| (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty());
if (!hasPersistence) {
throw new IllegalArgumentException(
"CopilotClient was created with Mode = EMPTY but neither CopilotHome nor CliUrl was set. "
+ "Empty mode requires an explicit per-session persistence location.");
}
}
// Parse CliUrl if provided
if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()) {
URI uri = CliServerManager.parseCliUrl(this.options.getCliUrl());
String host = uri.getHost();
this.optionsHost = host != null && host.startsWith("[") && host.endsWith("]")
? host.substring(1, host.length() - 1)
: host;
this.optionsPort = uri.getPort();
} else {
this.optionsHost = null;
this.optionsPort = null;
}
View on GitHub (pinned to cd8cf15dc3)