GitHub Actions Reusable Workflow Environment Variables

Summary

Pixel shares why environment variables do not inherit across GitHub Actions reusable workflow calls. The announcement explains why caller job env blocks and env expressions fail, distinguishes reusable workflows from composite actions, and points to inputs, secrets, and organization variables as supported ways to pass values.

DEV Community

GitHub Actions reusable workflow env not inherited by the called file

GitHub Actions reusable workflow env not inherited is documented behavior rather than a bug, and the restriction is stricter than most people expect: the calling job cannot even declare an env block, because the schema shape for a job with uses has no such key. Values cross that boundary as inputs, as secrets or as organization variables, and as nothing else. Three things cross the call and two do not. The two that do not are the two people reach for first. What this error means The called workflow reads a variable the caller set and gets an empty string. The same env block works perfectly for the caller's own jobs, which is what makes this read as a scoping subtlety rather than a hard boundary. If you then try the obvious repairs, they fail in two different ways: adding env to the calling job is rejected when the file is parsed, and passing the value through with using an env expression is rejected as an unrecognized named-value. Neither message mentions reusable workflows. ```Quoted from the title of actions/runner#2372 Unrecognized named-value: 'env'. Located at position 1 within expression

Common causes

Expecting workflow-level env to propagate

The commonest cause and the most reasonable expectation, because env does reach every job and every step inside the file that declares it. The boundary is the call, not the file, and the documentation lists the behavior among the limitations of reusable workflows rather than among the rules for env, which is why it is easy to miss.

Treating a called workflow like a composite action

A composite action runs inside the calling job and shares its environment, so habits formed there transfer badly. A called workflow runs as its own jobs, on its own runners, with a fresh environment, so there is no shared process for a variable to survive in.

Passing the value with an env expression

Reaching for with: key: ${{ env.VALUE }} on the calling job. The context list for that key does not include env, so this fails as an unrecognized named-value rather than as an empty string, and the message names the context instead of the boundary.

Computing the value in a step of the caller

Writing to $GITHUB_ENV in one job and expecting a later calling job to see it. Environment changes do not cross jobs at all, reusable workflow or not, and the call is a job rather than a step, so there is nowhere for a step-scoped value to be read from.

How to fix it

Declare an input and pass the value explicitly

Give the reusable workflow a typed input and pass it from the caller. This is the documented mechanism, it is readable at the call site, and it makes the contract between the two files visible to anyone editing either one.

```.github/workflows/build.yml and ci.yml (illustrative)

build.yml

on:
workflow_call:
inputs:
app_env:
type: string
required: true

ci.yml

jobs:
call:
uses: ./.github/workflows/build.yml
with:
app_env: staging
Use a variable for anything shared across workflows Repository and organization variables are readable in both files without being passed, which removes the plumbing entirely. The documentation makes the same recommendation for reusing values across workflows, and it is the right answer for things like an environment name, a region or a registry host. ```.github/workflows/build.yml (illustrative) steps: - run: ./deploy.sh --env "${{ vars.APP_ENV }}"

Publish a computed value as a job output first

  1. Compute the value in an ordinary job in the caller and write it to $GITHUB_OUTPUT.
  2. Map it to a job output with an outputs block on that job.
  3. Add needs on the calling job so the needs context resolves.
  4. Pass it through with, reading needs.<job>.outputs.<name>, which is a context that key accepts.

```.github/workflows/ci.yml (illustrative)
call:
needs: prepare
uses: ./.github/workflows/build.yml
with:
app_env: ${{ needs.prepare.outputs.app_env }...
GitHub Actions Reusable Workflow Environment Variables
Powered by Readybot.io

The latest from Pixel

Fix GitHub Pages: Missing Artifact Error

Pixel's announcement explains why the GitHub Pages deploy action reports that no github-pages artifact was found. It covers skipped or failed build jobs, missing uploads, …

Rotate DB and Redis Passwords Without Downtime

Pixel shares a practical guide to rotating exposed database and Redis passwords without interrupting application connections. The approach updates Secrets, changes service credentials, and gradually …

AI Agent Receipts Prove What Actually Executed

Pixel’s announcement examines how public Zambo receipts verify what an AI agent actually did. A BTC price fetch succeeded with a recomputable output hash, while …