Skip to content
Latchkey

GitHub Actions secrets cannot be used in if conditions

The secrets context is not available in every key. Job-level if is evaluated before secrets are in scope, so a condition like if: secrets.TOKEN != '' fails to gate as intended.

What this error means

A job or step that should run only when a secret is present runs (or skips) unexpectedly, or the workflow errors that secrets is not a recognized context in that location.

github-actions
Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.DEPLOY_KEY != ''

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

Job-level if cannot read secrets

The secrets context is not available in jobs.<id>.if; the condition errors or never matches.

Gating presence of a secret directly

Conditionals that branch on a secret value leak intent and are not supported at job scope.

How to fix it

Promote the secret to an env or output first

  1. Set a job-level env var from the secret, then branch on the env in a step.
  2. Or compute a boolean output in an early step and gate later steps on that output.
  3. Avoid referencing secrets.* inside jobs.<id>.if.
.github/workflows/deploy.yml
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      HAS_KEY: ${{ secrets.DEPLOY_KEY != '' }}
    steps:
      - if: env.HAS_KEY == 'true'
        run: ./deploy.sh

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

  • Never reference secrets.* in job-level if.
  • Convert secret presence to an env var or step output, then branch on that.

Frequently asked questions

What causes GitHub Actions secrets cannot be used in if conditions?
There are 2 common causes: job-level if cannot read secrets and gating presence of a secret directly. The secrets context is not available in jobs.<id>.if; the condition errors or never matches.
How do I fix GitHub Actions secrets cannot be used in if conditions?
Promote the secret to an env or output first. Set a job-level env var from the secret, then branch on the env in a step.
What does GitHub Actions secrets cannot be used in if conditions actually mean?
A job or step that should run only when a secret is present runs (or skips) unexpectedly, or the workflow errors that secrets is not a recognized context in that location.
How do I stop GitHub Actions secrets cannot be used in if conditions happening again?
Never reference secrets.* in job-level if. 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