# GitHub Actions concurrency in a reusable workflow cancels the wrong run in CI

> Fix concurrency problems with a reusable workflow in CI - a concurrency group inside the called workflow can cancel unrelated caller runs; scope the group with caller context.

Source: https://latchkey.dev/learn/github-actions/reusable-workflow-concurrency-cancels-caller-in-ci  
Updated: 2026-06-30

A `concurrency` group defined inside a reusable workflow is shared across every caller that uses it. If the group key is static, one caller's run cancels another's. Scope the key with caller context so groups stay independent.

## Diagnose it: what token do you actually have?

Permission failures in Actions are almost never about your repository settings alone. Three things combine: the default `GITHUB_TOKEN` permission set for the repo or organization, the `permissions:` block in the workflow, and whether the event is a fork pull request, which downgrades the token to read-only regardless of everything else.

```.github/workflows/ci.yml
- name: Show the token scopes actually granted
  run: |
    curl -sI -H "Authorization: Bearer $GITHUB_TOKEN" \
      https://api.github.com/ | grep -i "^x-oauth-scopes\|^x-accepted"
    echo "event: ${{ github.event_name }}"
    echo "fork PR: ${{ github.event.pull_request.head.repo.fork }}"
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

> If `fork PR` prints `true`, stop looking at `permissions:`. A fork pull request gets a read-only token by design, and no workflow-level grant can raise it.

## Grant the narrowest permission that works

Declaring a `permissions:` block switches the job from the repository default to exactly what you list, so an incomplete block is a common cause of a new failure right after someone tightened security. List every scope the job needs, not just the one that failed.

```.github/workflows/ci.yml
permissions:
  contents: read        # checkout
  packages: write       # push to GHCR
  id-token: write       # OIDC to a cloud provider
  pull-requests: write  # comment on or label a PR
  checks: write         # publish check runs
```

> Set `permissions` at the job level rather than the workflow level where you can. A workflow-level grant applies to every job, including ones that only run tests.

## FAQ

### What causes GitHub Actions concurrency in a reusable workflow cancels the wrong run in CI?

There are 2 common causes: a static concurrency group in the callee and no caller context in the group key. The reusable workflow sets concurrency: deploy-group with no per-caller context, so all callers land in one group and cancel each other.

### How do I fix GitHub Actions concurrency in a reusable workflow cancels the wrong run in CI?

There are 2 fixes depending on which cause you have: scope the concurrency group with context and set concurrency in the caller instead. Work through them in order, since the first is the most common.

### What does GitHub Actions concurrency in a reusable workflow cancels the wrong run in CI actually mean?

Runs from different branches or callers cancel each other unexpectedly, because the reusable workflow uses a fixed concurrency group name shared by all invocations.

### How do I stop GitHub Actions concurrency in a reusable workflow cancels the wrong run in CI happening again?

Include caller context in any concurrency group used by shared workflows. The prevention section lists 3 changes that keep it from recurring.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
