Skip to content
Latchkey

GitHub Actions Reusable Workflow "secret not defined" - Declare in workflow_call

A caller passes a secret to a reusable workflow that does not declare it under workflow_call.secrets, so the call is rejected - or the called workflow reads a secret that was never forwarded.

What this error means

The caller fails validation saying the secret is not defined in the called workflow, or the reusable workflow sees an empty secret because the caller did not pass it and did not use inherit.

Actions annotation
Invalid workflow file: secret 'DEPLOY_TOKEN' is not defined in the
referenced workflow .github/workflows/deploy.yml

Common causes

Secret not declared in workflow_call

A reusable workflow must list each secret it accepts under on.workflow_call.secrets. Passing an undeclared secret with secrets: { NAME: ... } is rejected.

Relying on inherit when explicit is needed

secrets: inherit forwards all caller secrets, but if you pass secrets explicitly the called workflow still must declare each one. Mixing the two incorrectly leaves a secret empty.

How to fix it

Declare secrets in the called workflow

deploy.yml (called)
# deploy.yml (called)
on:
  workflow_call:
    secrets:
      DEPLOY_TOKEN:
        required: true

Pass secrets explicitly or inherit

Either forward each declared secret by name, or use inherit to pass all caller secrets to a trusted called workflow.

.github/workflows/release.yml
# caller
jobs:
  call:
    uses: ./.github/workflows/deploy.yml
    secrets:
      DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
    # or, for a trusted callee: secrets: inherit

How to prevent it

  • Declare every secret a reusable workflow needs under workflow_call.secrets.
  • Pass secrets explicitly for least privilege; reserve inherit for trusted callees.
  • Document the secret contract alongside the inputs in the called workflow.

Related guides

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