github/copilot-sdk · error · IllegalArgumentException

GitHubToken and UseLoggedInUser cannot be used with CliUrl…

Error message

GitHubToken and UseLoggedInUser cannot be used with CliUrl (external server manages its own auth)

What it means

When CopilotClient connects to an external server via CliUrl, that server manages its own authentication, so supplying GitHubToken or UseLoggedInUser is contradictory. The constructor throws IllegalArgumentException to prevent conflicting auth configuration. Auth options are only meaningful when the client drives a local CLI.

Solutions

  1. Omit githubToken and useLoggedInUser when cliUrl is set — the external server authenticates itself.
  2. Conditionally set auth options only when cliPath/local-CLI mode is used.
  3. Move auth configuration to the external server instead of the client options.

Example fix

// before
options.setCliUrl("http://localhost:8080");
options.setGitHubToken(token); // not allowed with CliUrl
// after
options.setCliUrl("http://localhost:8080");
// no auth options — external server manages auth
Defensive patterns

Strategy: validation

Validate before calling

boolean external = options.getCliUrl() != null && !options.getCliUrl().isEmpty();
if (external && (options.getGitHubToken() != null || options.getUseLoggedInUser().isPresent())) {
    options.setGitHubToken(null);
}

Try / catch

try {
  client = new CopilotClient(options);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("cannot be used with CliUrl")) {
    options.setGitHubToken(null);
    client = new CopilotClient(options);
  } else throw e;
}

Prevention

When it happens

Trigger: Constructing CopilotClient with a non-empty cliUrl plus either a non-null githubToken or a present useLoggedInUser option.

Common situations: Reusing a shared options builder that always sets GitHubToken; switching from local CLI to external-server mode without removing auth fields; environment-injected tokens (e.g. GITHUB_TOKEN) wired into options unconditionally.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/7ba7fdad278d869b. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/CopilotClient.java:187

            }
        }
        this.runtimeConnection = requestedConnection;

        // When cliUrl is set, auto-correct useStdio since we're connecting via TCP
        if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()) {
            this.options.setUseStdio(false);
        }

        // Validate mutually exclusive options: cliUrl and cliPath cannot both be set
        if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()
                && this.options.getCliPath() != null) {
            throw new IllegalArgumentException("CliUrl is mutually exclusive with CliPath");
        }

        // Validate auth options with external server
        if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()
                && (this.options.getGitHubToken() != null || this.options.getUseLoggedInUser().isPresent())) {
            throw new IllegalArgumentException(
                    "GitHubToken and UseLoggedInUser cannot be used with CliUrl (external server manages its own auth)");
        }

        // Validate tcpConnectionToken
        if (this.options.getTcpConnectionToken() != null) {
            if (this.options.getTcpConnectionToken().isEmpty()) {
                throw new IllegalArgumentException("TcpConnectionToken must be a non-empty string");
            }
            if (this.options.isUseStdio()) {
                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

View on GitHub (pinned to cd8cf15dc3)