Skip to content
Latchkey

GHCR "denied: permission_denied: write_package" in CI

GHCR rejected the push because the token has no write scope for packages. The default GITHUB_TOKEN is read-only for packages unless the workflow grants permissions: packages: write. Add that permission (and log in with the token) and the push succeeds.

What this error means

Pushing to ghcr.io fails with "denied: permission_denied: write_package" even though docker login against ghcr.io with GITHUB_TOKEN reported success.

docker
The push refers to repository [ghcr.io/org/app]
denied: permission_denied: write_package

Common causes

The workflow token is missing packages: write

By default GITHUB_TOKEN can read packages but not write. Without the explicit permission, GHCR denies the push.

A restrictive default workflow permission

If the repo or org sets default token permissions to read-only, the job needs to opt back into packages: write.

How to fix it

Grant packages: write and log in with GITHUB_TOKEN

  1. Add a permissions block with packages: write (and contents: read).
  2. Log in to ghcr.io using ${{ github.actor }} and ${{ secrets.GITHUB_TOKEN }}.
  3. Push to ghcr.io/OWNER/IMAGE.
.github/workflows/ci.yml
permissions:
  contents: read
  packages: write
steps:
  - uses: docker/login-action@v3
    with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}

Use a PAT when pushing cross-repo

If the package lives outside the workflow repo, GITHUB_TOKEN may not suffice. Use a PAT with write:packages stored as a secret.

How to prevent it

  • Declare permissions: packages: write in workflows that push to GHCR.
  • Link the package to the repo so the workflow token can write to it.
  • Prefer GITHUB_TOKEN over long-lived PATs when the package is in-repo.

Frequently asked questions

What causes ""permission_denied: write_package""?
By default GITHUB_TOKEN can read packages but not write. Without the explicit permission, GHCR denies the push.
How do I fix "permission_denied: write_package"?
Grant packages: write and log in with GITHUB_TOKEN

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card