github/copilot-sdk · error · IllegalArgumentException
CopilotClient is in Mode = EMPTY but the resume session…
Error message
CopilotClient is in Mode = EMPTY but the resume session config did not specify availableTools. Empty mode requires every session to explicitly opt into the tools it wants — e.g. setAvailableTools(new ToolSet().addBuiltIn(BuiltInTools.ISOLATED)).
What it means
In CopilotClientMode.EMPTY the client never exposes tools implicitly: every session must explicitly declare its availableTools. When resuming a session in EMPTY mode whose config has availableTools == null, the client throws IllegalArgumentException because no tool filter could be derived.
Solutions
- Set availableTools on the resume config, e.g. new ToolSet().addBuiltIn(BuiltInTools.ISOLATED)
- Change the client mode away from EMPTY if implicit tools are desired
- Add a config-validation step before resume that rejects null availableTools in EMPTY mode
Example fix
// before client.resumeSession(config); // config.availableTools == null, mode == EMPTY // after config.setAvailableTools(new ToolSet().addBuiltIn(BuiltInTools.ISOLATED)); client.resumeSession(config);
Defensive patterns
Strategy: validation
Validate before calling
if (clientOptions.getMode() == CopilotClientMode.EMPTY && resumeConfig.getAvailableTools() == null) {
throw new IllegalArgumentException("EMPTY mode requires availableTools on resume config");
} Try / catch
try {
client.resumeSession(config);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("did not specify availableTools")) {
config.setAvailableTools(new ToolSet().addBuiltIn(BuiltInTools.ISOLATED));
client.resumeSession(config);
}
} Prevention
- Centralize resume-config construction so availableTools is always set in EMPTY mode
- Validate configs at load time (fail fast on missing availableTools when mode==EMPTY)
- Document EMPTY-mode requirements in your config schema
When it happens
Trigger: Calling resumeSession (or creating a resume request) on a client constructed with mode = EMPTY while the resume config's getAvailableTools() returns null.
Common situations: Code that worked in default mode reused for an EMPTY-mode client; config objects deserialized from JSON missing the availableTools field; migrating sessions to EMPTY mode without updating resume paths.
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
- CopilotClient is in Mode = EMPTY but the session config did…
- CopilotClient was created with Mode = EMPTY but neither…
- BuiltinPluginDirectories must contain only absolute paths…
- GitHubToken and UseLoggedInUser cannot be combined with…
- Invalid entry '*': there is no bare wildcard. Use `new…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/538316626e8b8d26.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/CopilotClient.java:1150
session.registerTransformCallbacks(extracted.transformCallbacks());
}
var request = SessionRequestBuilder.buildResumeRequest(sessionId, config, options.getMode());
if (extracted.wireSystemMessage() != config.getSystemMessage()) {
request.setSystemMessage(extracted.wireSystemMessage());
}
// Opt this session into GitHub telemetry forwarding when a
// connection-level handler is registered (mirrors the runtime's
// hand-written capability flag, not part of the codegen'd contract).
if (options.getOnGitHubTelemetry() != null) {
request.setEnableGitHubTelemetryForwarding(true);
}
// Empty mode: validate availableTools and set toolFilterPrecedence for resume
// path
if (options.getMode() == CopilotClientMode.EMPTY) {
if (config.getAvailableTools() == null) {
throw new IllegalArgumentException(
"CopilotClient is in Mode = EMPTY but the resume session config did not specify "
+ "availableTools. Empty mode requires every session to explicitly opt into "
+ "the tools it wants — e.g. setAvailableTools(new ToolSet().addBuiltIn(BuiltInTools.ISOLATED)).");
}
request.setToolFilterPrecedence("excluded");
if (request.getSkipEmbeddingRetrieval() == null) {
request.setSkipEmbeddingRetrieval(true);
}
if (request.getEmbeddingCacheStorage() == null) {
request.setEmbeddingCacheStorage("in-memory");
}
if (request.getEnableOnDemandInstructionDiscovery() == null) {
request.setEnableOnDemandInstructionDiscovery(false);
}
if (request.getEnableFileHooks() == null) {
request.setEnableFileHooks(false);
}
if (request.getEnableHostGitOperations() == null) {View on GitHub (pinned to cd8cf15dc3)