Summary
When multiple instances of the same gh-aw workflow are dispatched concurrently (e.g. via gh workflow run in a loop), some runs randomly fail because the conclusion job's concurrency group is a static string that doesn't include any run-specific identifier.
Problem
The compiled .lock.yml generates a conclusion job with:
conclusion:
needs: [activation, agent, safe_outputs]
if: (always()) && (needs.agent.result != 'skipped')
concurrency:
group: "gh-aw-conclusion-<workflow-name>"
cancel-in-progress: false
The concurrency group gh-aw-conclusion-<workflow-name> is shared across all runs of that workflow. When multiple runs reach the conclusion job at the same time, GitHub Actions serializes them — only one can run at a time. Queued jobs sometimes get cancelled (observed with runner_id: 0, meaning no runner was ever assigned).
Meanwhile, the workflow-level concurrency group is correctly scoped per-run using an input value:
concurrency:
group: my-workflow-${{ github.event.inputs.some_id }}
So the workflow itself handles concurrent runs fine, but the conclusion job undoes that by funneling everything through a single static group.
Observed behavior
Given 3 concurrent dispatches of the same workflow:
| Run |
agent job |
safe_outputs job |
conclusion job |
| A |
✅ success |
⏭️ skipped |
✅ success |
| B |
✅ success |
⏭️ skipped |
❌ cancelled (runner_id: 0) |
| C |
✅ success |
⏭️ skipped |
✅ success |
All three runs completed the agent job successfully. Run B's conclusion job was cancelled before a runner was assigned — the only difference between the runs.
Expected behavior
The conclusion job's concurrency group should be scoped per-run, e.g.:
concurrency:
group: "gh-aw-conclusion-<workflow-name>-${{ github.run_id }}"
cancel-in-progress: false
Or, if the workflow has an input that uniquely identifies the run, use that (matching the workflow-level pattern).
Workaround
Manually patching the .lock.yml to append a unique identifier to the concurrency group resolves the issue, but this gets overwritten on the next gh aw compile.
Environment
- gh-aw compiler version: v0.60.0
- GitHub Actions
- Reproduced with 3+ concurrent
workflow_dispatch runs of the same workflow
Summary
When multiple instances of the same gh-aw workflow are dispatched concurrently (e.g. via
gh workflow runin a loop), some runs randomly fail because theconclusionjob's concurrency group is a static string that doesn't include any run-specific identifier.Problem
The compiled
.lock.ymlgenerates aconclusionjob with:The concurrency group
gh-aw-conclusion-<workflow-name>is shared across all runs of that workflow. When multiple runs reach theconclusionjob at the same time, GitHub Actions serializes them — only one can run at a time. Queued jobs sometimes get cancelled (observed withrunner_id: 0, meaning no runner was ever assigned).Meanwhile, the workflow-level concurrency group is correctly scoped per-run using an input value:
So the workflow itself handles concurrent runs fine, but the
conclusionjob undoes that by funneling everything through a single static group.Observed behavior
Given 3 concurrent dispatches of the same workflow:
agentjobsafe_outputsjobconclusionjobAll three runs completed the
agentjob successfully. Run B'sconclusionjob was cancelled before a runner was assigned — the only difference between the runs.Expected behavior
The
conclusionjob's concurrency group should be scoped per-run, e.g.:Or, if the workflow has an input that uniquely identifies the run, use that (matching the workflow-level pattern).
Workaround
Manually patching the
.lock.ymlto append a unique identifier to the concurrency group resolves the issue, but this gets overwritten on the nextgh aw compile.Environment
workflow_dispatchruns of the same workflow