🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Fixes
Today I Fixed

GitHub Actions: permission denied to contents:write in workflow

gitJun 24, 202610 minutes to fixgithub-actionscicdtroubleshooting

GitHub Actions workflow was trying to push a commit back to the repo (updating a changelog file) and failed:

remote: Permission to org/repo.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/org/repo/': The requested URL returned error: 403

Root cause:

The default GITHUB_TOKEN permissions were read for contents. Workflows that need to push commits, create releases, or write to the repo need explicit write permission.

Since GitHub tightened defaults in 2022, the default permissions for GITHUB_TOKEN are read-only for most things.

Fix — add permissions to the workflow:

yaml
name: Update Changelog
 
on:
  push:
    branches: [main]
 
permissions:
  contents: write  # ← this line fixes it
 
jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
 
      - name: Update changelog
        run: |
          echo "## $(date +%Y-%m-%d)" >> CHANGELOG.md
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add CHANGELOG.md
          git commit -m "chore: update changelog [skip ci]"
          git push

Permission reference:

PermissionWhat it allows
contents: readRead repo files (default)
contents: writePush commits, create tags
pull-requests: writeCreate/update PRs
issues: writeCreate/comment on issues
packages: writePush to GitHub Packages
id-token: writeOIDC authentication (AWS, GCP)

Lesson: Always set the minimum required permissions explicitly in workflows. Don't use repo-wide permission overrides if you can scope it to the specific workflow. The [skip ci] in commit messages prevents infinite loops when bots commit.