Skip to content
LatchkeyLatchkey home

GitHub Actions GITHUB_TOKEN Read-Only by Default - Write Calls 403

A write API call fails with 403 because the repository or organization default for GITHUB_TOKEN is read-only. The default scope is set in repo/org Actions settings and overridden per workflow with permissions:.

What this error means

A step that pushes, comments, or creates a release fails with "Resource not accessible by integration" even though the workflow looks correct - the default token permission is read-only.

Actions log
RequestError [HttpError]: Resource not accessible by integration (status 403)
# repo Settings > Actions > Workflow permissions = "Read repository contents"

Diagnose 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.

.github/workflows/ci.yml
- 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

Repo/org default set to read-only

GitHub’s recommended default makes GITHUB_TOKEN read-only. Any write (contents, issues, packages) then 403s unless the workflow elevates it.

No permissions: block in the workflow

Without an explicit permissions: block, the job inherits the restrictive default, so write-needing steps are denied.

How to fix it

Grant the needed scope in the workflow

Add a least-privilege permissions: block at the workflow or job level for exactly what you write.

.github/workflows/ci.yml
permissions:
  contents: write     # only what this workflow needs
jobs:
  release:
    runs-on: ubuntu-latest
    steps: [{ run: ./publish.sh }]

Or adjust the repo/org default

  1. In Settings > Actions > General, the "Workflow permissions" setting controls the default token scope.
  2. Prefer keeping the default read-only and elevating per workflow with permissions:.
  3. Set permissions at the job level when only one job needs write access.

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.

.github/workflows/ci.yml
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 runs

How to prevent it

  • Keep the default token read-only and grant write per workflow.
  • Declare a least-privilege permissions: block in every write workflow.
  • Scope permissions to the job that needs them, not the whole workflow.

Frequently asked questions

What causes GitHub Actions GITHUB_TOKEN Read-Only by default?
There are 2 common causes: repo/org default set to read-only and no permissions: block in the workflow. GitHub’s recommended default makes GITHUB_TOKEN read-only.
How do I fix GitHub Actions GITHUB_TOKEN Read-Only by default?
There are 2 fixes depending on which cause you have: grant the needed scope in the workflow and or adjust the repo/org default. Work through them in order, since the first is the most common.
What does GitHub Actions GITHUB_TOKEN Read-Only by default actually mean?
A step that pushes, comments, or creates a release fails with "Resource not accessible by integration" even though the workflow looks correct - the default token permission is read-only.
How do I stop GitHub Actions GITHUB_TOKEN Read-Only by default happening again?
Keep the default token read-only and grant write per workflow. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card