Summary
Ruleset-required workflows in this repository use
concurrency.cancel-in-progress: true. When two pull_request events arrive
within about a second, two workflow runs are created for the same head SHA
and one is cancelled. Usually the cancelled run is the older one and everything
is fine. Occasionally the ordering inverts: the most recently created run is
the cancelled one, while an older run succeeded.
When that happens the required-workflows ruleset reports the workflow as
failed and the PR cannot merge — even though the check itself passed. The PR
stays blocked until something forces a fresh run.
Confirmed occurrence
lfreleng-actions/sigul-sign-docker#175, head SHA
bb87d81b6c7a8987671497c73dc219eaaef5fda2.
GraphQL state (still true at time of writing):
mergeable : MERGEABLE
mergeStateStatus : BLOCKED
rollup state : FAILURE
Semantic Pull Request / Semantic Pull Request CANCELLED 2026-08-13T14:04:35Z
Semantic Pull Request / Semantic Pull Request SUCCESS 2026-08-13T14:04:58Z
Merge attempt response:
Repository rule violations found / Required workflows failed
• Semantic Pull Request 🛠️
Workflow runs for that SHA:
| Workflow |
Created |
Conclusion |
Semantic Pull Request 🛠️ |
14:04:32 |
success |
Semantic Pull Request 🛠️ |
14:04:33 |
cancelled |
Note the inversion: the run that completed last is the successful one
(check run completed 14:04:58), but the run created last is the cancelled
one (created 14:04:33, cancelled 14:04:35 before the other had even started its
job at 14:04:39).
Every other workflow on the same SHA shows the same duplicate-run pattern with
the expected ordering, and none of them block:
| Workflow |
Older run |
Newer run |
AI Slop Scan 🧹 |
cancelled 14:04:31 |
success 14:04:33 |
Zizmor Scan 🌈 |
cancelled 14:04:31 |
success 14:04:32 |
Sigul Build/Test 🐳 |
cancelled 14:04:31 |
success 14:04:33 |
SHA Pinned Actions 📌 |
cancelled 14:04:32 |
success 14:04:33 |
Package Hardening Audit |
cancelled 14:04:32 |
success 14:04:33 |
Semantic Pull Request 🛠️ |
success 14:04:32 |
cancelled 14:04:33 |
Probable mechanism
Stated as inference — I have not found GitHub documentation that pins this down
precisely, so the maintainers may want to verify:
The required-workflows ruleset appears to evaluate the workflow run, and to
select the most recently created run for a given workflow, rather than the
most recently completed check run. In the case above that selects the
cancelled run, so the requirement is reported as failed despite a later
successful check run existing for the same SHA.
What is not in doubt: the check passed, a cancelled duplicate exists, and the
PR is blocked.
How often
Surveyed 160 recent PR head SHAs across eight repositories
(sigul-sign-docker, tag-validate-action, python-workflows,
docker-workflows, workflows-template, markdown-table-fixer, lftools-uv,
http-api-tool-docker):
- 164
(workflow, SHA) pairs had more than one run — duplicate runs are
routine, roughly one per SHA
- 1 had the newest run cancelled with a success present (~0.6%)
So it is rare, but it fails closed and blocks the PR indefinitely, and with
bulk automation merges running hundreds of PRs it will recur.
Exposure
Five ruleset-required workflows in this repository currently use
cancel-in-progress: true:
| File |
Group |
cancel-in-progress |
aislop.yaml |
${{ github.workflow }}-${{ github.ref }} |
true |
package-hardening-audit.yaml |
${{ github.workflow }}-${{ github.ref }} |
true |
semantic-pull-request.yaml |
${{ github.workflow }}-${{ github.ref }} |
true |
sha-pinned-actions.yaml |
${{ github.workflow }}-${{ github.ref }} |
true |
zizmor.yaml |
${{ github.workflow }}-${{ github.ref }} |
true |
All five are exposed to the same race. Only semantic-pull-request.yaml has
been observed hitting it so far.
By contrast repo-audit.yaml, release.yaml, aislop-sarif-publish.yaml and
zizmor-sarif-publish.yaml already set cancel-in-progress: false.
Suggested fix
Set cancel-in-progress: false on workflows that a ruleset marks as required:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: false
Rationale: a cancelled run of a required workflow can block a merge, so
cancellation is not a safe optimisation for this class of workflow. The cost of
letting both runs finish is small — the Semantic Pull Request job ran in
19 seconds (14:04:39 → 14:04:58). Both duplicate runs evaluate identical
inputs, so both would report the same result and no cancelled run would remain.
What will not work
Narrowing the concurrency group to include the head SHA, e.g.
${{ github.workflow }}-${{ github.event.pull_request.head.sha }}, does not
fix this. The two colliding events share a head SHA, so they would still land
in the same group and still cancel each other. The problem is the cancellation
itself, not the group key.
Possible refinement
If cancellation is worth keeping for the more expensive scans, it could be made
conditional on the event type — cancelling only on synchronize (a genuinely
superseded commit) and never on edited / reopened. That is more moving
parts than simply disabling it, so probably only worth it if the run cost
matters.
Recovering currently-stuck PRs
Re-running the cancelled workflow run, or otherwise generating a fresh run
(pushing a commit, editing the title), clears the block.
lfreleng-actions/sigul-sign-docker#175 is stuck on this right now and can
serve as a test case.
Context
Found while auditing a bulk automation-merge run over lfreleng-actions
(503 PRs). Related, but distinct:
lfit/releng-reusable-workflows#854 — the semantic check's Dependabot
title/subject relaxation misses mid-string version elision. Different root
cause; both surfaced as Semantic Pull Request 🛠️ failures in the same run.
lfreleng-actions/dependamerge#405 — tooling-side handling for the above.
Summary
Ruleset-required workflows in this repository use
concurrency.cancel-in-progress: true. When twopull_requestevents arrivewithin about a second, two workflow runs are created for the same head SHA
and one is cancelled. Usually the cancelled run is the older one and everything
is fine. Occasionally the ordering inverts: the most recently created run is
the cancelled one, while an older run succeeded.
When that happens the required-workflows ruleset reports the workflow as
failed and the PR cannot merge — even though the check itself passed. The PR
stays blocked until something forces a fresh run.
Confirmed occurrence
lfreleng-actions/sigul-sign-docker#175, head SHAbb87d81b6c7a8987671497c73dc219eaaef5fda2.GraphQL state (still true at time of writing):
Merge attempt response:
Workflow runs for that SHA:
Semantic Pull Request 🛠️Semantic Pull Request 🛠️Note the inversion: the run that completed last is the successful one
(check run completed 14:04:58), but the run created last is the cancelled
one (created 14:04:33, cancelled 14:04:35 before the other had even started its
job at 14:04:39).
Every other workflow on the same SHA shows the same duplicate-run pattern with
the expected ordering, and none of them block:
AI Slop Scan 🧹Zizmor Scan 🌈Sigul Build/Test 🐳SHA Pinned Actions 📌Package Hardening AuditSemantic Pull Request 🛠️Probable mechanism
Stated as inference — I have not found GitHub documentation that pins this down
precisely, so the maintainers may want to verify:
The required-workflows ruleset appears to evaluate the workflow run, and to
select the most recently created run for a given workflow, rather than the
most recently completed check run. In the case above that selects the
cancelled run, so the requirement is reported as failed despite a later
successful check run existing for the same SHA.
What is not in doubt: the check passed, a cancelled duplicate exists, and the
PR is blocked.
How often
Surveyed 160 recent PR head SHAs across eight repositories
(
sigul-sign-docker,tag-validate-action,python-workflows,docker-workflows,workflows-template,markdown-table-fixer,lftools-uv,http-api-tool-docker):(workflow, SHA)pairs had more than one run — duplicate runs areroutine, roughly one per SHA
So it is rare, but it fails closed and blocks the PR indefinitely, and with
bulk automation merges running hundreds of PRs it will recur.
Exposure
Five ruleset-required workflows in this repository currently use
cancel-in-progress: true:cancel-in-progressaislop.yaml${{ github.workflow }}-${{ github.ref }}truepackage-hardening-audit.yaml${{ github.workflow }}-${{ github.ref }}truesemantic-pull-request.yaml${{ github.workflow }}-${{ github.ref }}truesha-pinned-actions.yaml${{ github.workflow }}-${{ github.ref }}truezizmor.yaml${{ github.workflow }}-${{ github.ref }}trueAll five are exposed to the same race. Only
semantic-pull-request.yamlhasbeen observed hitting it so far.
By contrast
repo-audit.yaml,release.yaml,aislop-sarif-publish.yamlandzizmor-sarif-publish.yamlalready setcancel-in-progress: false.Suggested fix
Set
cancel-in-progress: falseon workflows that a ruleset marks as required:Rationale: a cancelled run of a required workflow can block a merge, so
cancellation is not a safe optimisation for this class of workflow. The cost of
letting both runs finish is small — the
Semantic Pull Requestjob ran in19 seconds (14:04:39 → 14:04:58). Both duplicate runs evaluate identical
inputs, so both would report the same result and no cancelled run would remain.
What will not work
Narrowing the concurrency group to include the head SHA, e.g.
${{ github.workflow }}-${{ github.event.pull_request.head.sha }}, does notfix this. The two colliding events share a head SHA, so they would still land
in the same group and still cancel each other. The problem is the cancellation
itself, not the group key.
Possible refinement
If cancellation is worth keeping for the more expensive scans, it could be made
conditional on the event type — cancelling only on
synchronize(a genuinelysuperseded commit) and never on
edited/reopened. That is more movingparts than simply disabling it, so probably only worth it if the run cost
matters.
Recovering currently-stuck PRs
Re-running the cancelled workflow run, or otherwise generating a fresh run
(pushing a commit, editing the title), clears the block.
lfreleng-actions/sigul-sign-docker#175is stuck on this right now and canserve as a test case.
Context
Found while auditing a bulk automation-merge run over
lfreleng-actions(503 PRs). Related, but distinct:
lfit/releng-reusable-workflows#854— the semantic check's Dependabottitle/subject relaxation misses mid-string version elision. Different root
cause; both surfaced as
Semantic Pull Request 🛠️failures in the same run.lfreleng-actions/dependamerge#405— tooling-side handling for the above.