Fix: GitHub Actions permission denied (EACCES, 403, or Permission to X denied)
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 integrationOr 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: 403Error: 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' eventError: Resource not accessible by personal access tokenThe 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_TOKENonly 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:
| Permission | Use case |
|---|---|
contents: read | Checkout code |
contents: write | Push commits, create releases |
pull-requests: write | Comment on PRs, create PRs |
issues: write | Create/comment on issues |
packages: write | Push to GitHub Container Registry |
pages: write | Deploy to GitHub Pages |
id-token: write | OIDC authentication (AWS, GCP) |
actions: read | Read workflow runs |
Pro Tip: Always use the minimum permissions needed. Setting
permissions: write-allworks 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 pushIf 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: trueFor pushing to a different branch:
- run: |
git checkout -b auto-fixes
git push origin auto-fixesFor 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:
Go to Settings → Actions → General
Under Workflow permissions, select:
- Read and write permissions (for most use cases)
- Or keep Read repository contents and set permissions per workflow
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: writein 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 ciThe 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.txtFor 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):
- Create a PAT at Settings → Developer Settings → Personal Access Tokens → Fine-grained tokens
- Add it as a repository secret: Settings → Secrets → Actions → New repository secret
- 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-imageFix: 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-imageRequires packages: write permission:
permissions:
packages: write
contents: readFor 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@v4Also 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.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Error: Process completed with exit code 1 (GitHub Actions)
How to fix 'Process completed with exit code 1' and other GitHub Actions workflow failures. Covers reading logs, exit codes, Node.js/Python/Docker step failures, secrets and environment variables, GITHUB_TOKEN permissions, checkout issues, caching, timeouts, self-hosted runners, matrix strategy, and artifacts.
Fix: YAML 'mapping values are not allowed here' and Other YAML Syntax Errors
How to fix 'mapping values are not allowed here', 'could not find expected :', 'did not find expected key', and other YAML indentation and syntax errors in Docker Compose, Kubernetes manifests, GitHub Actions, and config files.
Fix: Docker container health status unhealthy
How to fix Docker container health check failing with unhealthy status, including HEALTHCHECK syntax, timing issues, missing curl/wget, endpoint problems, and Compose healthcheck configuration.
Fix: AWS CloudFormation stack in ROLLBACK_COMPLETE or CREATE_FAILED state
How to fix AWS CloudFormation ROLLBACK_COMPLETE and CREATE_FAILED errors caused by IAM permissions, resource limits, invalid parameters, and dependency failures.