All guidesMore providers: databases, auth, hosting, email and payments
On this page

GitHub Actions question

GitHub

Why is my GitHub Actions secret empty in a pull request from a fork or from Dependabot?

By Ohad Krispin, founder of VibeRaven · LinkedIn

A GitHub Actions secret reads as an empty string when the run is triggered by a pull request from a forked repository or by a Dependabot event, because GitHub does not pass it to that run. GitHub's docs say secrets are not passed to the runner when a workflow is triggered from a forked repository, with GITHUB_TOKEN as the exception (read-only there), and that for Dependabot events the only secrets available are Dependabot secrets. A secret that was never set also evaluates to an empty string, and secrets are not passed to reusable workflows automatically. Store the value as a Dependabot secret with the same name, or move the step that needs it to a run you trust, such as a push to main.

Why does the same workflow work on my branch and fail on a contributor's pull request?

On a pull_request from a fork, the runner gets no secrets except GITHUB_TOKEN, and that token has read-only permissions. The workflow still starts, so a step that reads SUPABASE_ACCESS_TOKEN or a deploy token runs with an empty value and fails later with a message about authentication, not about the secret. GitHub also says workflows do not run in forked repositories by default.

env:
  SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

# pull request from a fork: SUPABASE_ACCESS_TOKEN is an empty string
# push to your own branch:  SUPABASE_ACCESS_TOKEN has the value

Why is the secret empty only on Dependabot pull requests?

GitHub's Dependabot troubleshooting page says that when a Dependabot event triggers a workflow, the only secrets available are Dependabot secrets, and GitHub Actions secrets are not available. Store the value as a Dependabot secret with the same name, so the same ${{ secrets.NAME }} line works for both. The same page says workflows triggered by Dependabot get a read-only GITHUB_TOKEN by default, and the permissions key in the workflow can raise it. A step that writes to the repository fails otherwise.

Can I test whether a secret is set?

GitHub says secrets cannot be referenced directly in if: conditionals, and suggests setting them as job-level environment variables and referencing those. A secret that is not set returns an empty string, so a skip condition on the variable works. Use it to skip a deploy or migration job on runs that cannot have the secret, and keep the tests that need no secret running.

jobs:
  migrate:
    runs-on: ubuntu-latest
    env:
      SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
    steps:
      - uses: actions/checkout@v4
      - if: env.SUPABASE_ACCESS_TOKEN != ''
        run: npm run db:migrate

Can I switch to pull_request_target to get the secrets back?

GitHub's Dependabot page lists a two-step process with pull_request_target as a way around these limits. The events page says that event runs in the context of the default branch of the base repository, warns that running untrusted code on it may lead to security vulnerabilities, and says to avoid it if you need to build or run code from the pull request. Do not check out and run a fork's code in a job that has your Supabase or Vercel tokens.

Checklist

How to find the cause, then fix it

  1. 01Open the failed run and read the event and the actor: a pull request from a fork, dependabot[bot], or your own branch.
  2. 02
    Print whether the value is set, without printing it:
    if [ -n "$SUPABASE_ACCESS_TOKEN" ]; then echo set; else echo empty; fi
  3. 03For Dependabot, add the same secret name as a Dependabot secret. For a reusable workflow, pass each secret in explicitly, because GitHub does not pass them automatically.
  4. 04For a fork, run only the tests that need no secret on the pull_request event, and run the jobs that need Supabase or Vercel tokens after the merge, on a push to the default branch.
  5. 05Check the secret name in the repository settings against the name in the workflow, letter for letter: an unset or misspelled name gives an empty string, not an error.

Related

Sources

Official docs behind this checklist

FAQ

FAQ for builders before launch

What does a secret that is not set return?

GitHub says the expression returns an empty string. The workflow does not stop with an error, so the failure shows up in whatever step uses the value.

Does GITHUB_TOKEN work in a fork pull request?

It is passed, as the exception to the secrets rule, but with read-only permissions. A step that comments on the pull request or pushes a commit fails there.

Does the same happen to a Supabase or Vercel token in my deploy workflow?

Yes, when that workflow runs on a pull request from a fork or on a Dependabot event. On a push to your own branch the Actions secret is passed as usual. The token scopes are covered on the Supabase personal access token page.