GitHub Actions input required and not supplied: token error
The GitHub Actions input required and not supplied: token error comes from @actions/core, which read an environment variable, found it empty, and threw. The word after the colon is the name of the action's input, which is usually not the name of whatever you set.

What this error means
The step fails within a second of starting and nothing else in the job is affected. The message names token, so the search begins for a secret called token, and there is rarely one. Steps earlier in the same job that use other secrets work, which makes the whole thing look like a problem with this action specifically rather than with the value it received.
##[error]Input required and not supplied: tokenWhat the check actually does
The function is four lines. getInput builds an environment variable name by taking the input name, replacing spaces with underscores, uppercasing it and prefixing INPUT_. It reads that variable, defaulting to an empty string if it is absent. Then, if the caller passed required and the value is empty, it throws the message on this page with the input name interpolated into it.
Two things follow. The check cannot distinguish an input that was never provided from one that was provided as an empty string, because both arrive as an empty value. And the name in the message is always the action's input name, chosen by whoever wrote the action, and never the name of your secret or variable.
Common causes
The secret referenced in the with: block does not exist under that name
The common case. A misspelling, a secret created in a different repository, or a name that was changed in settings and not in the workflow all produce an empty interpolation. Nothing warns about referencing a secret that is not there; the expression simply resolves to an empty string.
The job cannot receive secrets on this event
A pull request from a fork gets no repository secrets at all, so every reference empties at once. The workflow is unchanged and correct, and the same step passes on a push. If several secret-dependent steps fail together, this is usually why.
The secret exists at a scope this job cannot read
An organization secret not shared with the repository, or an environment secret in a job that does not name the environment, both resolve to empty. In our experience the environment case is the most persistent, because the secret is plainly visible in settings and the job simply is not in the environment that holds it.
A reusable workflow was called without the secret being passed
The called workflow sees only what the caller forwarded. Without secrets: inherit or an explicit mapping, a step inside it that requires a token gets an empty string, and the failure is reported from a file that never mentions your secret.
How to fix it
Read the with: block before the settings page
- Find the failing step and the line whose left-hand side matches the name in the message.
- Take the name on the right-hand side, which is yours, and confirm it exists at a scope this job can read.
- If there is no such line, the action expected an input it has no default for, and one has to be supplied.
Delete the override when the action has a working default
If the action declares default: ${{ github.token }} for the input, passing a secret that does not exist is strictly worse than passing nothing. Removing the line restores the default and often ends the problem outright.
Name the environment when the secret lives in one
An environment secret is only readable by a job that declares the environment. The declaration belongs on the job, and adding it changes which secrets the job can see.
jobs:
publish:
runs-on: ubuntu-latest
environment: production
steps:
- uses: some-org/publish-action@v2
with:
token: ${{ secrets.PUBLISH_TOKEN }}Forward secrets into a reusable workflow
Pass them explicitly when you want to see what crosses the boundary, or inherit them when the called workflow is yours and the list would be long. The choice is about reviewability rather than correctness.
jobs:
call-publish:
uses: ./.github/workflows/publish.yml
secrets:
PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}Three names that are easy to conflate
A value passes through three naming schemes before the check sees it, and the message only ever mentions the middle one.
| Name | Who chooses it | Whether it appears in the message |
|---|---|---|
The secret or variable, such as RELEASE_TOKEN | You, in repository or organization settings | No |
The action's input, such as token | The action author, in its action.yml | Yes, this is the word after the colon |
The environment variable, such as INPUT_TOKEN | The runner, derived from the input name | No, but it is what is actually read |
Why a default in the action does not always save you
Many actions declare a default for their token input, commonly ${{ github.token }}, and the runner evaluates that before the step starts. With such a default, the input is only empty when you overrode it, which makes an explicit with: line the first thing to examine rather than the last.
That inverts the usual instinct. The step that has no token: line at all is generally the one that works, and the step that carefully passes a secret is the one that fails, because passing an empty secret replaces a working default with nothing. Deleting the line is a legitimate repair and is frequently the right one.
Why there is no recorded run on this page
The check does not touch the network, the filesystem or the runner's state; it reads one environment variable and compares it to the empty string. Recording that would produce a single line identical to the one above, and it would tell you nothing about which of your names, scopes or events left the variable empty, which is the entire question. What can be established once and reused is the transformation from a secret name to an input name to a variable name, and that is fixed in the toolkit's source.
How to prevent it
- Keep the action's input name and your secret name visibly different, so the message is never mistaken for your name.
- Let a documented default stand unless a different identity is genuinely needed.
- Declare the environment on any job that reads environment secrets, at the time you write the job.
- When a workflow must run on fork pull requests, guard the steps that need secrets rather than letting them fail.
Frequently asked questions
I have no secret called token. Where is that name from?
getInput interpolates the input name it was asked for, and that name is declared in the action's action.yml. Your own name appears only on the right-hand side of the mapping in the step's with: block, and the check never sees it.Does the message mean the input was missing or empty?
Why do several steps fail with different messages at once?
Is removing the token line really a fix?
action.yml for a default before adding a secret to solve this.