Skip to content
Latchkey

GitHub Actions composite action cannot access secrets directly

Composite actions cannot read the secrets context directly; only the calling workflow can. A composite action that references secrets.* gets an unrecognized context error or an empty value - secrets must be passed in as inputs.

What this error means

A composite action fails validation referencing secrets.*, or a secret it expected is empty at runtime.

github-actions
Error: Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.NPM_TOKEN

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 }}

Common causes

Direct secrets reference inside composite

The composite action body references secrets.NPM_TOKEN, but the secrets context is not exposed to composite actions.

How to fix it

Pass the secret in as an input

  1. Declare an input on the composite action for the secret value.
  2. In the calling workflow, pass the secret via with.
  3. Reference inputs.<name> inside the composite action; re-run.
action.yml + caller
# action.yml (composite)
inputs:
  npm-token:
    required: true
runs:
  using: composite
  steps:
    - run: npm publish
      shell: bash
      env:
        NODE_AUTH_TOKEN: ${{ inputs.npm-token }}
# caller workflow
- uses: ./.github/actions/publish
  with:
    npm-token: ${{ secrets.NPM_TOKEN }}

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

How to prevent it

  • Pass secrets into composite actions as explicit inputs.
  • Never reference the secrets context inside composite action bodies.

Frequently asked questions

What causes GitHub Actions composite action cannot access secrets directly?
direct secrets reference inside composite. The composite action body references secrets.NPM_TOKEN, but the secrets context is not exposed to composite actions.
How do I fix GitHub Actions composite action cannot access secrets directly?
Pass the secret in as an input. Declare an input on the composite action for the secret value.
What does GitHub Actions composite action cannot access secrets directly actually mean?
A composite action fails validation referencing secrets.*, or a secret it expected is empty at runtime.
How do I stop GitHub Actions composite action cannot access secrets directly happening again?
Pass secrets into composite actions as explicit inputs. The prevention section lists 2 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card