GitHub Actions "Input required and not supplied: token"
An action declared token as a required input, but it arrived empty - usually a secret that does not exist, is named wrong, or was not passed to a reusable workflow.
What this error means
An action fails at startup with "Input required and not supplied: token". The action never runs because its required token input resolved to an empty string.
Error: Input required and not supplied: tokenDiagnose 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.
- 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 }}Common causes
Secret missing or misnamed
with: token: ${{ secrets.MY_TOKEN }} resolves to empty when the secret does not exist or is spelled differently than defined.
Secret not passed to a reusable workflow or fork
A reusable workflow only sees secrets explicitly passed (or inherited). On a fork pull_request, secrets are unavailable, so the token input is empty.
How to fix it
Supply a real token input
Pass a defined secret (or the built-in GITHUB_TOKEN) to the action’s token input.
- uses: some/action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}Make sure the secret reaches the job
- Confirm the secret name matches exactly what is stored in repo/org/environment settings.
- For reusable workflows, forward the secret via the secrets: block or secrets: inherit.
- Remember fork pull_request runs get no secrets - gate token-using steps accordingly.
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.
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 runsHow to prevent it
- Reference secret names exactly as defined.
- Forward secrets explicitly to reusable workflows.
- Guard token-dependent steps so fork PRs do not run them with empty secrets.