Skip to content

Fix: GitHub Actions permission denied (EACCES, 403, or Permission to X denied)

FixDevs ·

Quick Answer

How to fix GitHub Actions permission denied errors caused by GITHUB_TOKEN permissions, checkout issues, artifact access, npm/pip cache, and Docker socket access.

The Error

Your GitHub Actions workflow fails with:

Error: HttpError: Resource not accessible by integration

Or variations:

remote: Permission to user/repo.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/user/repo.git/': The requested URL returned error: 403
Error: EACCES: permission denied, open '/home/runner/.npm/_cacache/...'
Error: Process completed with exit code 128.
hint: The 'user/repo' repository doesn't match the 'push' event
Error: Resource not accessible by personal access token

The workflow does not have permission to perform the action. GitHub Actions uses tokens with specific scopes, and the default permissions might not be enough.

Why This Happens

GitHub Actions provides a GITHUB_TOKEN that is automatically available in every workflow. This token has limited permissions that vary based on the trigger event and repository settings.

Common causes:

  • Default token permissions too restrictive. GitHub’s default is read-only for most permissions since 2023.
  • Pushing code requires write access. The default token cannot push to the repo without explicit contents: write.
  • Creating PRs or issues requires write access. The default token cannot interact with issues/PRs without pull-requests: write.
  • Accessing other repositories. The GITHUB_TOKEN only works for the current repository.
  • Forked repository restrictions. Pull requests from forks have read-only tokens for security.
  • File permission issues in the runner. npm, pip, or Docker need specific file permissions.

Fix 1: Set Workflow Permissions

Add explicit permissions at the workflow or job level:

Workflow-level permissions:

name: CI
on: push

permissions:
  contents: write
  pull-requests: write
  issues: write
  packages: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Has write access"

Job-level permissions (more granular):

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4

  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pages: write
      id-token: write
    steps:
      - run: echo "Deploy with write access"

Common permission scopes:

PermissionUse case
contents: readCheckout code
contents: writePush commits, create releases
pull-requests: writeComment on PRs, create PRs
issues: writeCreate/comment on issues
packages: writePush to GitHub Container Registry
pages: writeDeploy to GitHub Pages
id-token: writeOIDC authentication (AWS, GCP)
actions: readRead workflow runs

Pro Tip: Always use the minimum permissions needed. Setting permissions: write-all works but is a security risk. List only the specific permissions your workflow requires. This follows the principle of least privilege.

Fix 2: Fix Git Push Permissions

Pushing commits from a workflow requires contents: write:

jobs:
  auto-fix:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          # Make changes...
          git add .
          git commit -m "Auto-fix"
          git push

If push still fails with 403:

The actions/checkout action uses the GITHUB_TOKEN by default. Verify the token has write access:

- uses: actions/checkout@v4
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
    persist-credentials: true

For pushing to a different branch:

- run: |
    git checkout -b auto-fixes
    git push origin auto-fixes

For general git push errors, see Fix: error: failed to push some refs.

Fix 3: Fix Repository Settings

The repository’s default permissions might override workflow settings:

  1. Go to SettingsActionsGeneral

  2. Under Workflow permissions, select:

    • Read and write permissions (for most use cases)
    • Or keep Read repository contents and set permissions per workflow
  3. Check Allow GitHub Actions to create and approve pull requests if your workflow creates PRs.

For organization repositories:

Organization-level settings can restrict Actions permissions for all repos. Check:

Settings → Actions → General (at the organization level).

Common Mistake: Setting permissions: contents: write in the workflow but the repository setting restricts the token to read-only. The repository setting takes precedence. Ask a repository admin to update the settings.

Fix 4: Fix Forked Repository Permissions

Pull requests from forks always have read-only GITHUB_TOKEN. This is a security feature — a fork could run malicious code with write access to the upstream repo.

Workaround — use pull_request_target for trusted operations:

on:
  pull_request_target:
    types: [opened, synchronize]

jobs:
  label:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - run: |
          gh pr edit ${{ github.event.pull_request.number }} --add-label "needs-review"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Warning: pull_request_target runs with the base branch’s code and token permissions. Never checkout and execute code from the forked PR with pull_request_target — this is a security vulnerability.

Fix 5: Fix npm and pip Cache Permissions

File permission errors in the GitHub Actions runner:

Error: EACCES: permission denied, mkdir '/home/runner/.npm'

Fix for npm:

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: 'npm'

- run: npm ci

The actions/setup-node action handles caching properly. If you manage caching manually:

- name: Cache npm
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}

Fix for pip:

- uses: actions/setup-python@v5
  with:
    python-version: '3.12'
    cache: 'pip'

- run: pip install -r requirements.txt

For npm permission errors in general, see Fix: npm EACCES permission denied global install.

Fix 6: Use a Personal Access Token (PAT)

When the GITHUB_TOKEN is insufficient (e.g., triggering workflows in other repos, accessing private repos):

  1. Create a PAT at Settings → Developer Settings → Personal Access Tokens → Fine-grained tokens
  2. Add it as a repository secret: Settings → Secrets → Actions → New repository secret
  3. Use it in the workflow:
steps:
  - uses: actions/checkout@v4
    with:
      token: ${{ secrets.MY_PAT }}

  - run: |
      git push
    env:
      GITHUB_TOKEN: ${{ secrets.MY_PAT }}

For cross-repository access:

- uses: actions/checkout@v4
  with:
    repository: org/other-repo
    token: ${{ secrets.MY_PAT }}

Note: PATs have broader access than GITHUB_TOKEN. Use fine-grained tokens with minimum required permissions, and set an expiration date.

Fix 7: Fix Docker Permissions

Docker commands might need special permissions in the runner:

- name: Build and push
  run: |
    docker build -t my-image .
    docker push ghcr.io/user/my-image

Fix: Log in to the container registry:

- name: Login to GHCR
  uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
  run: |
    docker build -t ghcr.io/${{ github.repository }}/my-image .
    docker push ghcr.io/${{ github.repository }}/my-image

Requires packages: write permission:

permissions:
  packages: write
  contents: read

For Docker permission issues outside GitHub Actions, see Fix: Docker permission denied socket.

Fix 8: Fix GitHub Pages Deployment

Deploying to GitHub Pages requires specific permissions:

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/configure-pages@v4
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
      - id: deployment
        uses: actions/deploy-pages@v4

Also enable Pages in the repository: Settings → Pages → Source: GitHub Actions.

Still Not Working?

Check the Actions log for the exact error. The error message usually specifies which permission is missing.

Check for branch protection rules. If the target branch has protection rules requiring PR reviews or status checks, the GITHUB_TOKEN cannot bypass them (even with contents: write).

Check for CODEOWNERS. If the repository has a CODEOWNERS file requiring specific reviewers, automated PRs might be blocked.

Check for IP allowlists. GitHub Enterprise organizations might restrict Actions to specific IP ranges.

Check token expiration. Fine-grained PATs expire. If a workflow suddenly stops working, check if the PAT expired.

Debug the GITHUB_TOKEN permissions:

- name: Check token permissions
  run: |
    curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
      https://api.github.com/repos/${{ github.repository }} | jq '.permissions'

For other GitHub Actions failures, see Fix: GitHub Actions process completed with exit code 1.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles