Skip to content

GITHUB_TOKEN env var not updated after credential refresh, breaking all gh CLI operations #1135

@jwm4

Description

@jwm4

Problem

When GITHUB_TOKEN expires mid-session, calling refresh_credentials (the MCP tool) refreshes the backend credentials — the git credential helper (/tmp/git-credential-ambient) returns a valid fresh token — but the GITHUB_TOKEN shell environment variable retains the stale value. Since the gh CLI prioritizes GITHUB_TOKEN over all other credential sources, every gh command fails with 401 Bad credentials even though valid credentials are available.

This affects all gh operations: gh pr create, gh api, gh repo list, gh issue view, gh search issues, etc.

Steps to reproduce

  1. Start a session with GitHub integration connected
  2. Wait for the GITHUB_TOKEN to expire (or observe it mid-session)
  3. Call refresh_credentials MCP tool — it reports success
  4. Run gh auth status — fails with "The token in GITHUB_TOKEN is invalid"
  5. Verify the credential helper has a fresh token:
    FRESH_TOKEN=$(printf 'protocol=https\nhost=github.com\n\n' | git credential fill 2>/dev/null | grep '^password=' | cut -d= -f2)
    echo "Token length: ${#FRESH_TOKEN}"  # Returns 40, confirming a token exists
  6. Override the env var inline — works:
    GITHUB_TOKEN="$FRESH_TOKEN" gh auth status  # Succeeds
  7. But the next gh command in a new shell invocation fails again because GITHUB_TOKEN is re-injected with the stale value

Expected behavior

After refresh_credentials is called, gh commands should work. Either:

  1. The GITHUB_TOKEN env var should be updated to the fresh token, or
  2. The stale GITHUB_TOKEN should be cleared so gh falls through to the credential helper

Actual behavior

  • GITHUB_TOKEN retains the expired value across all shell invocations
  • gh reads the stale env var and returns 401 on every call
  • The credential helper has a valid token but gh never consults it because GITHUB_TOKEN takes precedence

Impact

  • PR creation fails (both gh pr create and searching for existing forks/issues)
  • No gh api calls work, blocking any GitHub API interaction
  • Workaround exists (inline GITHUB_TOKEN=fresh gh ... per command) but is fragile since fresh tokens also appear to be short-lived

Workaround

The updated PR skill in workflows/bugfix/.claude/skills/pr/SKILL.md documents this workaround:

FRESH_TOKEN=$(printf 'protocol=https\nhost=github.com\n\n' | git credential fill 2>/dev/null | grep '^password=' | cut -d= -f2)
GITHUB_TOKEN="$FRESH_TOKEN" gh auth status

This works for individual commands but must be repeated for each invocation because the shell env is re-initialized with the stale token each time.

Relationship to #935

Issue #935 addresses the type of token (installation tokens lack cross-fork PR permissions). This issue addresses the delivery of the token (the env var goes stale mid-session). They are complementary — even with #935's proposed OAuth user-to-server tokens, those tokens would still go stale if the env var isn't synced after refresh.


This issue was filed by Claude Code under the supervision of Bill Murdock.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai-triagedIssue has been triaged by AI automationamber:auto-fixAmber agent: automated low-risk fixes (formatting, linting)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions