ci(auto-update-prs): a denied token was reported as six merge conflicts - #681
Merged
Conversation
The first live run of this workflow after the RELEASE_PAT switch (run 31136847506, 2026-08-07) failed to update all six open PRs with: GraphQL: Resource not accessible by personal access token (updatePullRequestBranch) and reported the result as `conflicted: 6` — then exited green. Two defects, both in the same else-branch: 1. A 403 is not a conflict. The branch treated every non-zero exit as a merge conflict, so a token-scope problem was rendered as six PRs "needing manual merge". That sends six authors to resolve conflicts that do not exist, while the single real cause — a secret missing a permission — appears nowhere in the output. 2. It exited green. A conflict is per-PR and rightly non-fatal, but a denial fails every PR identically and silently stops the whole workflow from doing its job. The symptom is an absence (no back-merge, no new CI run), so nothing surfaces it. #676 added a guard for the token being *absent* and this is the same silent-green failure one step later: presence was checked, permission was not. Classify the failure on the API's own wording, count denials separately, and exit non-zero when any occur. Conflicts stay non-fatal and per-PR, as documented at the top of the file. An unrecognised error still falls through to the conflict path — non-fatal — so a new failure mode cannot start failing the run spuriously. Note: this makes the misconfiguration visible; it does not repair it. RELEASE_PAT still needs 'pull_requests: write' (fine-grained) or 'repo' (classic) before auto-update can work at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What happened
The first live run of
auto-update-prs.ymlafter #676'sRELEASE_PATswitch (run 31136847506, 2026-08-07) failed to update all six open PRs:…and the job exited green.
Two defects, same
else-branch1. A 403 is not a conflict. Every non-zero exit was reported as a merge conflict. So a token-scope problem was rendered as six PRs "needing manual merge" — sending six authors after conflicts that do not exist, while the actual cause (a secret missing a permission) appeared nowhere.
2. It exited green. A conflict is per-PR and rightly non-fatal — that is deliberate and documented at the top of the file. A denial is not: it fails every PR identically and stops the workflow doing its job at all. The symptom is an absence — no back-merge, no new CI run — so nothing surfaces it.
#676 added a guard for the token being absent. This is the same silent-green failure one step later: presence was checked, permission was not.
The change
gh pr update-branchoutput and classify on the API's own wording.exit 1when any denial occurs, with an error naming the required scope.Testing
Classifier exercised against the real error string from the failed run, plus adversarial cases (principle #14 — the negative case is the point):
GraphQL: Resource not accessible by personal access token (updatePullRequestBranch)HTTP 403: ForbiddenHTTP 401: Bad credentialsmerge conflict between base and headGraphQL: Merge conflict (updatePullRequestBranch)actionlintclean.yamllint -c .yamllint.ymlreports only the pre-existingdocument-startwarning, verified present onmain's copy too.This does not fix the workflow
It makes the breakage loud.
RELEASE_PATstill needspull_requests: write(fine-grained) orrepo(classic) before auto-update can work at all — a secrets change. Expect this workflow to now fail visibly on the next push to main until that scope is granted. That is the intended outcome: a red run naming the cause beats a green run reporting six phantom conflicts.🤖 Generated with Claude Code