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

  1. When GitHub Actions fails on push, check permissions first. The permissions: contents: write setting is now commonly needed for any workflow that modifies the repository.

  2. Monitor your automated workflows. Don’t assume that because something worked last week, it’s still working today.

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