{"record":{"id":"70b9e6c24a6f9566","repo":"github/copilot-sdk","slug":"copilotclient-was-created-with-mode-empty-but-ne","errorCode":null,"errorMessage":"CopilotClient was created with Mode = EMPTY but neither CopilotHome nor CliUrl was set. Empty mode requires an explicit per-session persistence location.","messagePattern":"CopilotClient was created with Mode = EMPTY but neither CopilotHome nor CliUrl was set\\. Empty mode requires an explicit per-session persistence location\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/CopilotClient.java","lineNumber":215,"sourceCode":"                throw new IllegalArgumentException(\"TcpConnectionToken cannot be used with UseStdio = true\");\n            }\n        }\n\n        // Compute effective connection token: use provided, or auto-generate for\n        // SDK-spawned TCP mode, or null for stdio/external server\n        boolean sdkSpawnsCli = !this.options.isUseStdio()\n                && (this.options.getCliUrl() == null || this.options.getCliUrl().isEmpty());\n        this.effectiveConnectionToken = this.options.getTcpConnectionToken() != null\n                ? this.options.getTcpConnectionToken()\n                : (sdkSpawnsCli ? java.util.UUID.randomUUID().toString() : null);\n\n        // Empty mode: validate at construction time that the app supplied a\n        // per-session persistence location.\n        if (this.options.getMode() == CopilotClientMode.EMPTY) {\n            boolean hasPersistence = (this.options.getCopilotHome() != null && !this.options.getCopilotHome().isEmpty())\n                    || (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty());\n            if (!hasPersistence) {\n                throw new IllegalArgumentException(\n                        \"CopilotClient was created with Mode = EMPTY but neither CopilotHome nor CliUrl was set. \"\n                                + \"Empty mode requires an explicit per-session persistence location.\");\n            }\n        }\n\n        // Parse CliUrl if provided\n        if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()) {\n            URI uri = CliServerManager.parseCliUrl(this.options.getCliUrl());\n            String host = uri.getHost();\n            this.optionsHost = host != null && host.startsWith(\"[\") && host.endsWith(\"]\")\n                    ? host.substring(1, host.length() - 1)\n                    : host;\n            this.optionsPort = uri.getPort();\n        } else {\n            this.optionsHost = null;\n            this.optionsPort = null;\n        }\n","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/CopilotClient.java#L197-L233","documentation":"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.","triggerScenarios":"new CopilotClient(...) with options.setMode(CopilotClientMode.EMPTY) and both getCopilotHome() null/empty and getCliUrl() null/empty.","commonSituations":"Switching a client to EMPTY mode for isolation but forgetting to set a per-session CopilotHome; building options dynamically where both fields stayed null.","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"],"exampleFix":"// before\noptions.setMode(CopilotClientMode.EMPTY);\n// after\noptions.setMode(CopilotClientMode.EMPTY);\noptions.setCopilotHome(\"/tmp/copilot-session-\" + sessionId);","handlingStrategy":"validation","validationCode":"if (mode == CopilotClientMode.EMPTY && isBlank(home) && isBlank(cliUrl)) throw new IllegalArgumentException(\"EMPTY mode needs copilotHome or cliUrl\");","typeGuard":null,"tryCatchPattern":"try { new CopilotClient(options); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"Mode = EMPTY\")) { options.setCopilotHome(...); } else throw e; }","preventionTips":["Always pair EMPTY mode with a per-session copilotHome","Centralize client construction so the pairing cannot be forgotten"],"tags":["java","configuration","empty-mode","persistence"],"backgroundTag":"missing-required-config-field","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"}