Skip to content

ci: branch-cleanup.yml is an invalid workflow file (workflows is not a permission scope) — 1,163 consecutive failed runs on every push, including main #1405

Description

@groupthinking

Objective

.github/workflows/branch-cleanup.yml is rejected by GitHub as an invalid workflow file. Every push to every branch — including main — produces an instantly-failed run. The workflow has never successfully executed, and its red check is what holds otherwise-green PRs at mergeable_state: unstable.

One-line fix, no logic change.

Root cause

The permissions: block declares a scope that does not exist:

permissions:
  contents: write
  pull-requests: read
  workflows: write        # <-- not a valid permission scope

Per the workflow syntax reference, the valid keys are actions, artifact-metadata, attestations, checks, code-quality, contents, deployments, discussions, id-token, issues, packages, pages, pull-requests, security-events, statuses, vulnerability-alerts. workflows is not among them.

The confusion is understandable: workflow is a real scope for PATs and OAuth apps (the one needed to push changes to files under .github/workflows/). It is not grantable to GITHUB_TOKEN via the permissions: block, so this key never granted anything — it only invalidated the file.

Evidence

The failure signature is distinctive and matches an unparseable workflow rather than a failing job:

  • Runs are named by file path (.github/workflows/branch-cleanup.yml) instead of by the name: field (Branch Cleanup). GitHub falls back to the path when it cannot load the workflow.
  • created_at, run_started_at, and updated_at are byte-identical — e.g. all three are 2026-08-05T10:20:38Z on run 30997035127. Zero duration; no job ever starts.
  • Runs fire on branches the trigger filter excludes. The file declares on.push.branches: ["claude/branch-cleanup-*"], yet runs exist on main, groupthinking-fix-upstream-error-leakage, dependabot/github_actions/github/gh-aw-actions/setup-0.84.0, and others. An invalid file is reported on every push regardless of its filters.

Scale, from the workflow's own run history:

Metric Value
Total runs 1,163
Conclusion failure100%, no successes
Latest run numbers sampled 1134–1163, all failed
Distinct branches affected in one 30-run page 10, including main

It is also the only workflow in the repository using this key — a survey of the permissions: blocks across .github/workflows/*.yml (top-level and per-job) yields actions, checks, contents, deployments, id-token, issues, pull-requests, security-events, statuses, workflows, and branch-cleanup.yml is the sole source of that last one. It is likewise the only workflow producing this failure signature.

Acceptance criteria

  • branch-cleanup.yml loads: a push produces a run named Branch Cleanup, not the file path.
  • The run is a no-op success on branches without a sentinel commit, rather than a failure (the decide step already handles this via go=no).
  • No run is created on branches outside claude/branch-cleanup-* once the file is valid.
  • Otherwise-green PRs stop reading mergeable_state: unstable on account of this check.

Remediation

 permissions:
   contents: write
   pull-requests: read
-  workflows: write

The header comment above it should be corrected too — it currently claims the token needs "contents: write and workflows: write rights to delete/restore refs."

Removing the key changes no effective permission, because an invalid key grants nothing; the workflow has never run with it in force.

Declared file scope

  • .github/workflows/branch-cleanup.yml

Risk

  • Risk level: low. Deleting an ineffective key from a workflow that has never executed.
  • Failure mode: none for the delete path — branch deletion and archive-tag pushes need contents: write, which is retained.
  • Worth verifying on first real run: the restore path (git push origin "refs/tags/archive/$b:refs/heads/$b") recreates a ref whose tree may contain .github/workflows/ files. GITHUB_TOKEN is restricted from creating or updating workflow files, and no permissions: key can lift that. If restore fails that way, it is a pre-existing latent constraint this fix merely makes reachable for the first time — not a regression. It would need a PAT with the workflow scope, or a restore performed locally.
  • Rollback: revert the one-line change.

Notes

Found while driving PR #1381 through its CI gate under the PR remediation runbook. #1381's substantive checks (CI, CodeQL, Security Scan, Coverage, PR Checks, PR Governance, Secret Scan, Dependency Review) are all green on 36645ad; this invalid workflow is the remaining red mark.

I have not landed the fix. My branch assignment for this session is claude/clever-heisenberg-pedqbz, which already carries #1404 with a different canonical issue, and PR Governance requires one issue per PR — so folding an unrelated CI fix into it would break that gate. Happy to open it as its own PR on request; it is a one-line diff.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions