GitHub Actions "Resource not accessible by personal access token" (fine-grained)
Fine-grained PATs grant narrow per-permission scopes per repository. A call fails with 403 when the token has access to the repo but not the specific permission (contents, pull-requests, issues, etc.) the call needs.
What this error means
A step using a fine-grained PAT fails with resource not accessible by personal access token.
RequestError [HttpError]: Resource not accessible by personal access token
status: 403Diagnose it: what token do you actually have?
Permission failures in Actions are almost never about your repository settings alone. Three things combine: the default GITHUB_TOKEN permission set for the repo or organization, the permissions: block in the workflow, and whether the event is a fork pull request, which downgrades the token to read-only regardless of everything else.
- name: Show the token scopes actually granted
run: |
curl -sI -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/ | grep -i "^x-oauth-scopes\|^x-accepted"
echo "event: ${{ github.event_name }}"
echo "fork PR: ${{ github.event.pull_request.head.repo.fork }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Common causes
Missing fine-grained permission
The PAT lacks the exact permission (e.g. Pull requests: write) the operation requires.
Repository not selected
The fine-grained PAT does not include the target repository in its allowed list.
How to fix it
Grant the needed permission
- Edit the fine-grained PAT under Developer settings.
- Add the specific repository and grant the exact permission (e.g. Contents: write, Pull requests: write).
- Update the secret holding the token and re-run.
Grant the narrowest permission that works
Declaring a permissions: block switches the job from the repository default to exactly what you list, so an incomplete block is a common cause of a new failure right after someone tightened security. List every scope the job needs, not just the one that failed.
permissions:
contents: read # checkout
packages: write # push to GHCR
id-token: write # OIDC to a cloud provider
pull-requests: write # comment on or label a PR
checks: write # publish check runsHow to prevent it
- Map each automation to the minimal fine-grained permissions it needs.
- Prefer GITHUB_TOKEN with a permissions block when no cross-repo access is required.