Skip to content
Latchkey

GitHub Actions env at Workflow vs Job vs Step - Wrong Value Wins

An env variable holds an unexpected value because env is defined at multiple levels. Step env overrides job env, which overrides workflow env - the most specific definition wins for that step.

What this error means

A step reads an env var that is different from what the workflow-level env block sets, because a job- or step-level env block of the same name shadows it.

.github/workflows/ci.yml
env:
  NODE_ENV: production       # workflow level
jobs:
  test:
    env:
      NODE_ENV: test          # job level overrides workflow
    steps:
      - run: echo "$NODE_ENV" # prints "test", not "production"

Common causes

Same env name defined at multiple levels

GitHub merges env from workflow, job, and step scopes. When the same key exists at more than one level, the more specific scope wins for that step.

Assuming workflow env is global and final

A workflow-level env block is a default, not a lock. A job or step can redefine the key, so the workflow value is not guaranteed downstream.

How to fix it

Define each variable at one intended scope

Put shared defaults at the workflow level and only override deliberately at job or step level.

.github/workflows/ci.yml
env:
  REGION: us-east-1          # default for all jobs
jobs:
  deploy:
    steps:
      - run: ./deploy.sh
        env:
          REGION: eu-west-1   # intentional per-step override

Trace which scope set the value

  1. Echo the variable in the failing step to see the effective value.
  2. Search the workflow for every env: block defining that key.
  3. Remove accidental redefinitions; keep only the scope you intend to win.

How to prevent it

  • Keep each env key defined at a single intended scope.
  • Treat workflow-level env as defaults that jobs may override on purpose.
  • Echo effective env values when debugging precedence.

Frequently asked questions

What causes "env scope precedence"?
GitHub merges env from workflow, job, and step scopes. When the same key exists at more than one level, the more specific scope wins for that step.
How do I fix env scope precedence?
Put shared defaults at the workflow level and only override deliberately at job or step level.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card