When Your Automation Quietly Breaks: A Lesson in GitHub Actions Permissions
Thereâs a particular kind of frustration that comes with automation that almost works. Your system runs fine locally, passes all the tests, and then silently fails in production for reasons that seem completely unrelated to your code.
Todayâs culprit: a missing permissions line in a GitHub Actions workflow.
The Setup
I run an automated blogging system called AutoBlog that generates daily posts from my Claude Code session transcripts. The architecture is straightforward: GitHub Actions runs on a schedule, reads the transcripts, generates a blog post using Claude, and commits it to the repository.
It had been working fine. Then it wasnât.
The Symptom
The workflow logs showed everything proceeding normallyâtranscripts read, post generated, git commit createdâuntil the final step:
remote: Permission to username/autoblog.git denied to github-actions[bot].
fatal: unable to access '...': The requested URL returned error: 403
A 403 on git push. The GitHub Actions bot didnât have permission to push to its own repository.
The Investigation
My first instinct was to check if something had changed with the repository settings or branch protection rules. Nothing had. The workflow file hadnât been modified in days.
I never definitively identified what triggered the change. GitHub has been progressively tightening its default permissions modelâas of late 2024, workflows run with read-only access by default unless you explicitly grant write permissions. Whether my workflow hit a policy update or some other trigger, I canât say for certain. But the fix was clear once I understood the permissions model.
The Fix
The solution was adding three lines to the workflow file:
permissions:
contents: write
Thatâs it. This explicitly grants the GITHUB_TOKEN permission to push commits back to the repository.
Hereâs a minimal workflow demonstrating the structure:
name: Daily Blog Generation
on:
schedule:
- cron: '0 12 * * *' # Noon UTC
workflow_dispatch:
permissions:
contents: write
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate and commit post
run: |
# Your generation script here
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "Add daily blog post" || exit 0
git push
The permissions key can be set at the workflow level or at individual jobs if you need more granular control.
Debugging With AI Assistance
This bug highlights something useful about working with AI coding assistants: theyâre excellent at diagnosing infrastructure issues once you know where to look.
When I described the 403 error to Claude Code, it immediately identified the permissions model and suggested the fix. The error message âPermission denied to github-actions[bot]â is technically descriptive, but it doesnât scream âadd a permissions block to your workflow file.â An AI assistant that has encountered thousands of similar CI/CD issues can quickly map that symptom to its solution.
The skill on my end was recognizing this was worth investigating with the assistant rather than assuming something was fundamentally broken with my GitHub configuration. Knowing when to bring in helpâand what context to provideâmakes these debugging sessions far more effective.
Silent Breakage in CI/CD
This incident fits a pattern Iâve seen repeatedly: GitHub Actions workflows donât break immediately. They break the next time they run after some external condition changes. Your workflow can sit untouched for weeks and then fail because of a platform policy update, a dependency change, or a configuration that aged out of compatibility.
The lesson isnât to avoid GitHub Actionsâitâs to treat workflow files as production code that needs monitoring. Set up failure notifications. Use the workflow_dispatch trigger to test workflows on demand. And when you figure out why something broke, add a comment explaining the fix.
Takeaways
-
When GitHub Actions fails on push, check permissions first. The
permissions: contents: writesetting is now commonly needed for any workflow that modifies the repository. -
Monitor your automated workflows. Donât assume that because something worked last week, itâs still working today.
-
Document your workflow requirements. When you figure out why something broke, add a comment explaining why that configuration is necessary. Future you will thank present you.
The workflow is running again. Tomorrowâs post should generate automatically. And Iâve added this permissions quirk to my mental model of things that can quietly break in CI/CD pipelinesâright alongside expired tokens, deprecated actions, and runner image updates.
Some lessons only stick when your automation teaches them to you the hard way.