{"record":{"id":"6be564d960f98646","repo":"github/copilot-sdk","slug":"githubtoken-and-githubtokenprovider-cannot-be-used","errorCode":null,"errorMessage":"GitHubToken and GitHubTokenProvider cannot be used together.","messagePattern":"GitHubToken and GitHubTokenProvider cannot be used together\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Client.cs","lineNumber":2062,"sourceCode":"    /// always registered because providers are configured per session.\n    /// </summary>\n    private ClientGlobalApiHandlers? BuildClientGlobalApis()\n    {\n        var handler = _options.RequestHandler;\n        var onGitHubTelemetry = _options.OnGitHubTelemetry;\n        return new ClientGlobalApiHandlers\n        {\n            LlmInference = handler is null ? null : new LlmInferenceAdapter(handler, () => _serverRpc),\n            GitHubTelemetry = onGitHubTelemetry is null ? null : new GitHubTelemetryAdapter(onGitHubTelemetry, _logger),\n            GitHubToken = new GitHubTokenAdapter(this),\n        };\n    }\n\n    private static void ValidateGitHubTokenConfig(SessionConfigBase config)\n    {\n        if (config.GitHubToken is not null && config.GitHubTokenProvider is not null)\n        {\n            throw new ArgumentException(\n                $\"{nameof(SessionConfigBase.GitHubToken)} and {nameof(SessionConfigBase.GitHubTokenProvider)} cannot be used together.\",\n                nameof(config));\n        }\n    }\n\n    private string? RegisterGitHubTokenProvider(\n        Func<GitHubTokenProviderArgs, Task<GitHubTokenProviderResult>>? provider)\n    {\n        if (provider is null)\n        {\n            return null;\n        }\n\n        var registrationId = Guid.NewGuid().ToString();\n        if (!_gitHubTokenProviders.TryAdd(registrationId, provider))\n        {\n            throw new InvalidOperationException(\"Failed to register GitHub token provider.\");\n        }","sourceCodeStart":2044,"sourceCodeEnd":2080,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/Client.cs#L2044-L2080","documentation":"Thrown as ArgumentException by config validation when a session configuration supplies both GitHubToken (a static token) and GitHubTokenProvider (a delegate/provider callback). These two ways of supplying GitHub credentials are mutually exclusive by design, so the library refuses the configuration up front rather than guessing which to use.","triggerScenarios":"Creating a session (CreateSessionAsync/StartSessionAsync) with a SessionConfig where both config.GitHubToken is set to a string AND config.GitHubTokenProvider is set to a delegate.","commonSituations":"Merging config from two sources (e.g. a default template with a token plus app code adding a provider); switching from token-based to provider-based auth while leaving the old token property set; copy-pasted sample code combining both options.","solutions":["Remove GitHubToken and keep only GitHubTokenProvider, or vice versa","If merging config objects, decide precedence explicitly and null out the unused property","Centralize GitHub credential configuration in one place to avoid both being set"],"exampleFix":"// before\nvar config = new SessionConfig { GitHubToken = token, GitHubTokenProvider = myProvider };\n// after\nvar config = new SessionConfig { GitHubTokenProvider = myProvider }; // or GitHubToken = token, not both","handlingStrategy":"validation","validationCode":"if (config.GitHubToken is not null && config.GitHubTokenProvider is not null)\n    throw new ArgumentException(\"Set only one of GitHubToken or GitHubTokenProvider\");","typeGuard":"bool HasExactlyOneGitHubCredential(SessionConfig c) => (c.GitHubToken is null) != (c.GitHubTokenProvider is null);","tryCatchPattern":"try { await client.CreateSessionAsync(config); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"cannot be used together\"))\n{ logger.LogError(ex, \"conflicting GitHub credential config\"); throw; }","preventionTips":["Choose one credential mechanism per app (token OR provider)","Null out the other property when building merged configs","Validate session config in a shared factory","Document the exclusivity in your config schema"],"tags":["configuration","authentication","argument-validation","github-token","dotnet"],"backgroundTag":"mutually-exclusive-options","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"}