Skip to content

Confusing error when GITHUB_TOKEN (Actions installation token) is set in env #3396

@baiwei0427

Description

@baiwei0427

Bug

When copilot -p ... is invoked in a GitHub Actions job, an installation
token from secrets.GITHUB_TOKEN (or GH_TOKEN) is silently picked up
by the CLI and forwarded to the Copilot backend, which rejects it with:

[ERROR] Error loading models: Error: 400 "checking server-to-server token:
bad request: GitHub App Server-To-Server Tokens are not supported for
this endpoint"
[DEBUG] runPromptMode: executePromptDirectly returned succeeded=false
[DEBUG] runPromptMode: exiting with code 1

The CLI then exits 1 with no message on stderr — only the Braille
spinner and the MCP-policy warning are visible. The actual cause is
buried in ~/.copilot/logs/process-*.log.

Repro

Inside a GitHub Actions step that previously authenticated copilot as
a user (e.g. on a self-hosted runner where ~/.copilot/config.json
exists):

- name: Use Copilot CLI
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # needed for the `gh` CLI elsewhere in the workflow
  run: copilot --model gpt-5.5 --effort low -p "say hi"

Exits with code 1, no clear error on stderr. Removing the GH_TOKEN
env block makes the same command succeed.

Expected behaviour

One of:

  1. Auto-ignore the installation token. If GH_TOKEN/GITHUB_TOKEN
    starts with ghs_ (the prefix for GitHub Actions installation
    tokens), the CLI should treat it as not-for-me and fall back to
    ~/.copilot/config.json user auth.

  2. Emit a clear error on stderr. Something like:

    error: GITHUB_TOKEN looks like a GitHub Actions installation token
    (server-to-server). Copilot CLI requires a user-scoped token.
    Either:
      - unset GH_TOKEN/GITHUB_TOKEN before invoking copilot, or
      - log in once on this machine with `copilot` (interactive).
    

    Currently the user has to dig into ~/.copilot/logs/ to find the
    real cause, which is a poor experience in CI where logs are
    ephemeral.

Workaround (what I'm doing today)

Wrap copilot calls in a script that does unset GH_TOKEN GITHUB_TOKEN
before invocation, or use env -i with a minimal allowlist.

Why this matters

Code-review / lint / docs-generation CI jobs typically need both:

  • gh pr diff, gh pr comment (which want GH_TOKEN set), AND
  • copilot -p "review this diff" (which wants GH_TOKEN unset).

Currently you can't have both in one shell without the wrapper trick.
It also makes onboarding new CI integrators painful — the failure mode
is silent and the real error is only in a debug log file.

Environment

  • GitHub Copilot CLI: 1.0.49
  • Runner: self-hosted (Ubuntu 22.04 on WSL2)
  • Auth: user-scoped, stored in ~/.copilot/config.json

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authenticationLogin, OAuth, device auth, token management, and keychain integrationarea:non-interactiveNon-interactive mode (-p), CI/CD, ACP protocol, and headless automation

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions