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.
The push refers to repository [ghcr.io/org/app]
denied: permission_denied: write_packageCommon 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
- Add a
permissionsblock withpackages: write(andcontents: read). - Log in to ghcr.io using
${{ github.actor }}and${{ secrets.GITHUB_TOKEN }}. - Push to
ghcr.io/OWNER/IMAGE.
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: writein 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.