Skip to content
Latchkey

Secret is empty on a fork pull_request in CI

Secrets are not passed to workflows triggered by a pull_request from a fork. The expression resolves to an empty string, so steps that need a token or key fail as if it were unset, even though the secret exists.

What this error means

A step that uses ${{ secrets.X }} fails with an empty/missing value, but only on PRs opened from forks; same-repo PRs and pushes work.

.github/workflows/ci.yml
# event: pull_request from a fork
Error: Input required and not supplied: token
# secrets.MY_TOKEN evaluated to ""

Common causes

Forks do not receive secrets on pull_request

To prevent secret exfiltration by untrusted code, GitHub omits secrets from fork-triggered pull_request runs.

The step assumes the secret is always present

The workflow has no guard for the empty case, so a downstream action errors on the missing input.

How to fix it

Guard steps that need secrets

  1. Skip secret-dependent steps when the secret is empty (typical for fork PRs).
  2. Run those steps only on push or same-repo PRs.
  3. Move trusted writes to a workflow_run job in the base context.
.github/workflows/ci.yml
- name: Deploy
  if: ${{ secrets.MY_TOKEN != '' }}
  run: ./deploy.sh

Use a separate trusted workflow for secret work

Process untrusted PR output in a workflow_run workflow that runs with repository secrets in the base context.

.github/workflows/ci.yml
on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]

How to prevent it

  • Assume secrets are empty on fork pull_request runs.
  • Guard secret-dependent steps with an if check.
  • Keep trusted work in workflow_run or push-triggered jobs.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →