The GitHub Actions runner lost its permission to access the GitHub API, specifically when trying to perform actions like pushing to repositories or creating releases.

Cause 1: Expired or Revoked Personal Access Token (PAT)

  • Diagnosis: Check the secrets.GITHUB_TOKEN or any custom PATs used in your workflow. If you’re using a custom PAT, navigate to your GitHub Developer Settings -> Personal access tokens. Look for the token being used by your workflow. If it’s expired or revoked, you’ll see it listed there.
  • Fix:
    • For secrets.GITHUB_TOKEN: This token is automatically generated and its permissions are tied to the repository’s permissions for Actions. Ensure the permissions block in your workflow has the necessary scopes. For example, to push to the repo:
      permissions:
        contents: write
      
      To create releases:
      permissions:
        contents: read
        deployments: write
      
    • For custom PATs: Generate a new PAT with the required scopes (e.g., repo for full repository access, workflow for managing workflows). Update the repository’s secrets (Settings -> Secrets and variables -> Actions) with the new token’s value under the same secret name (e.g., MY_PAT).
  • Why it works: The GITHUB_TOKEN is a temporary token that grants permissions based on the context of the workflow run. If those permissions are insufficient or if a custom PAT has expired, the API calls will fail with a 403. Re-granting or adjusting permissions provides the necessary credentials.

Cause 2: Insufficient GITHUB_TOKEN Permissions

  • Diagnosis: Examine the permissions block in your workflow YAML file. If it’s missing or doesn’t include the required scopes (e.g., contents: write for pushing, actions: write for triggering other workflows), the GITHUB_TOKEN will lack the necessary privileges.
  • Fix: Add or modify the permissions block in your workflow file at the top level or for specific jobs.
    name: My Workflow
    
    on: [push]
    
    permissions:
      contents: write # Grant write access to repository contents
      # actions: write # Uncomment if you need to trigger other workflows
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Push changes
            run: |
              git config user.name "GitHub Actions"
              git config user.email "actions@github.com"
              git add .
              git commit -m "Automated commit"
              git push
    
  • Why it works: The GITHUB_TOKEN’s effective permissions are determined by the permissions block. Explicitly granting the required scopes (contents: write, packages: write, deployments: write, actions: write, etc.) ensures the token has the authority to perform the intended API operations.

Cause 3: Repository/Organization-Level IP Allowlist Restrictions

  • Diagnosis: If your GitHub Enterprise instance or organization has IP allowlisting enabled for API access, and the GitHub Actions runner’s IP address is not on the list, API calls will be denied. Check your organization’s or repository’s Settings -> Security -> IP Allow List.
  • Fix: Add the IP address ranges used by GitHub-hosted runners (or your self-hosted runners) to the IP allowlist. For GitHub-hosted runners, you can often find documentation for their IP ranges, or you might need to allow traffic from GitHub’s general IP blocks. If using self-hosted runners, ensure their egress IPs are whitelisted.
  • Why it works: IP allowlisting acts as a network-level gatekeeper. By adding the correct IP addresses, you permit traffic from GitHub Actions runners to reach the GitHub API.

Cause 4: Actions Runner Token Expiration (Self-Hosted Runners)

  • Diagnosis: For self-hosted runners, the registration token used to connect the runner to GitHub expires after 90 days. If this token has expired, the runner might not be able to authenticate properly with the GitHub API, leading to permission errors. Check the runner’s configuration and logs for messages related to token expiration or authentication failures.
  • Fix: Re-register your self-hosted runner. Generate a new registration token from your repository or organization’s Settings -> Actions -> Runners -> New runner. Use this new token when setting up your runner.
    ./config.sh --url https://github.com/your-org/your-repo --token YOUR_NEW_REGISTRATION_TOKEN
    
  • Why it works: The registration token is a one-time use credential that establishes the initial trust between the runner and GitHub. An expired token means the runner cannot re-authenticate or maintain its connection, thus losing its ability to act on behalf of the repository.

Cause 5: Incorrectly Configured GITHUB_TOKEN for Forked Repositories

  • Diagnosis: When a workflow runs on a pull request from a fork, the GITHUB_TOKEN has read-only permissions by default for security reasons. If your workflow attempts to push commits or create releases in this context, it will fail. Check the workflow logs for errors indicating a lack of write permissions specifically when processing PRs from forks.
  • Fix: In your workflow file, you can explicitly grant write permissions for contents if you trust the fork or are aware of the security implications.
    name: Build on PR
    
    on:
      pull_request:
        branches: [ main ]
    
    permissions:
      contents: write # Required to push to the repo from a fork PR
    
    jobs:
      # ... your jobs ...
    
    Note: This is generally discouraged for security reasons unless absolutely necessary. Consider alternative strategies like requiring a review before merging that automatically triggers the action on the base branch.
  • Why it works: By default, GitHub locks down the GITHUB_TOKEN for PRs from forks to prevent malicious code in a fork from pushing changes to the main repository. Explicitly setting contents: write overrides this default for the specific workflow run.

Cause 6: Actions Environment Variables Not Set Correctly

  • Diagnosis: If your workflow relies on custom environment variables that are supposed to hold API keys or tokens (instead of using GitHub Secrets), and these variables are not set or are set incorrectly in the Actions environment, API calls will fail. Check the workflow logs to see if the expected variables are populated.
  • Fix: Ensure all necessary environment variables are defined as GitHub Secrets. Access them in your workflow using the secrets context.
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - name: Deploy to Production
            env:
    
              PROD_API_KEY: ${{ secrets.MY_PRODUCTION_API_KEY }}
    
            run: |
              curl -H "Authorization: Bearer $PROD_API_KEY" https://api.example.com/deploy
    
  • Why it works: GitHub Secrets are encrypted and securely injected into the workflow environment. Using them ensures that sensitive credentials are not exposed in plain text in the workflow file and are correctly available to the running jobs.

The next error you’ll likely encounter after resolving these permission issues is a 404 Not Found if the API endpoint you’re trying to access doesn’t exist, or a 5xx Server Error if the GitHub API itself is experiencing an issue.

Want structured learning?

Take the full Github-actions course →