{"record":{"id":"aa3f21ed177c096b","repo":"github/copilot-sdk","slug":"copilotclient-was-created-with-mode-copilotclien","errorCode":null,"errorMessage":"CopilotClient was created with Mode = CopilotClientMode.Empty but neither BaseDirectory nor SessionFs was set. Empty mode requires an explicit per-session persistence location; pick one.","messagePattern":"CopilotClient was created with Mode = CopilotClientMode\\.Empty but neither BaseDirectory nor SessionFs was set\\. Empty mode requires an explicit per-session persistence location; pick one\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Client.cs","lineNumber":209,"sourceCode":"        _onListModels = _options.OnListModels;\n\n        _clientGlobalApis = BuildClientGlobalApis();\n\n        // Empty mode: validate at construction time that the app supplied a\n        // per-session persistence location. The runtime is mode-agnostic, so\n        // without this check it would silently fall back to ~/.copilot, which\n        // defeats the point of empty mode for multi-tenant scenarios.\n        if (_options.Mode == CopilotClientMode.Empty)\n        {\n            var hasPersistence =\n                !string.IsNullOrEmpty(_options.BaseDirectory) ||\n                _options.SessionFs is not null ||\n                // External runtimes manage their own persistence layer; the SDK\n                // can't enforce it from here.\n                _connection is UriRuntimeConnection;\n            if (!hasPersistence)\n            {\n                throw new ArgumentException(\n                    \"CopilotClient was created with Mode = CopilotClientMode.Empty but neither \" +\n                    \"BaseDirectory nor SessionFs was set. Empty mode requires an explicit \" +\n                    \"per-session persistence location; pick one.\",\n                    nameof(options));\n            }\n        }\n    }\n\n    /// <summary>\n    /// Validates environment-variable options against the resolved transport.\n    /// Per-client environment is only representable for child-process transports\n    /// (each client owns its own OS process). The in-process (FFI) transport\n    /// loads the native runtime into the shared host process, whose single\n    /// environment block cannot carry per-client values, so environment and\n    /// telemetry options that lower to environment variables are rejected there.\n    /// </summary>\n    private static void ValidateEnvironmentOptions(CopilotClientOptions options, RuntimeConnection connection)\n    {","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/Client.cs#L191-L227","documentation":"CopilotClientMode.Empty requires an explicit per-session persistence location: BaseDirectory or SessionFs on the options, or an external UriRuntimeConnection (which manages its own persistence). The constructor throws ArgumentException when Empty mode is selected without any of these.","triggerScenarios":"new CopilotClient(options) where options.Mode == CopilotClientMode.Empty, BaseDirectory is null, SessionFs is null, and Connection is not a UriRuntimeConnection.","commonSituations":"Switching modes to Empty for isolation but forgetting to set a storage location; refactoring options builders where BaseDirectory was dropped; assuming Empty mode defaults to a temp directory (it deliberately does not).","solutions":["Set options.BaseDirectory to a directory for per-session persistence","Set options.SessionFs to a session filesystem implementation","Or use an external runtime via RuntimeConnection.ForUri which manages persistence itself, or choose a non-Empty mode"],"exampleFix":"// before\nvar options = new CopilotClientOptions { Mode = CopilotClientMode.Empty };\n// after\nvar options = new CopilotClientOptions { Mode = CopilotClientMode.Empty, BaseDirectory = Path.Combine(appData, \"sessions\", sessionId) };","handlingStrategy":"validation","validationCode":"if (options.Mode == CopilotClientMode.Empty && options.BaseDirectory is null && options.SessionFs is null && options.Connection is not UriRuntimeConnection) throw new InvalidOperationException(\"Empty mode requires BaseDirectory or SessionFs\");","typeGuard":null,"tryCatchPattern":"try { client = new CopilotClient(options); } catch (ArgumentException ex) when (ex.Message.Contains(\"CopilotClientMode.Empty\")) { options.BaseDirectory ??= defaultSessionDir; client = new CopilotClient(options); }","preventionTips":["Set BaseDirectory/SessionFs whenever choosing Empty mode","Build options through a factory that enforces Empty-mode invariants","Add a startup unit test for each CopilotClientMode variant"],"tags":["dotnet","configuration","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"}