Skip to content
Latchkey

GitHub Actions Job Outputs Empty in a Downstream Job (needs.outputs)

A value set in one job is empty in another because job outputs were not declared. Step outputs do not cross job boundaries automatically - the job must export them under outputs:.

What this error means

A downstream job reads needs.<job>.outputs.<name> and gets an empty string, even though the upstream step wrote the value to GITHUB_OUTPUT correctly.

.github/workflows/ci.yml
# downstream
echo "version is ${{ needs.build.outputs.version }}"
# prints "version is " - empty

Common causes

Job did not declare outputs

Step outputs are local to the job. To expose a value to needs:, the job must map it under jobs.<id>.outputs from a step id.

Wrong step id or output name

The mapping must reference steps.<id>.outputs.<name> exactly. A mismatched step id or output key yields an empty job output.

How to fix it

Map step outputs to job outputs

Give the step an id, write to GITHUB_OUTPUT, and expose it under the job outputs block.

.github/workflows/ci.yml
jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.v.outputs.version }}
    steps:
      - id: v
        run: echo "version=1.2.3" >> "$GITHUB_OUTPUT"
  use:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "${{ needs.build.outputs.version }}"

Verify the names line up

  1. Confirm the step id in steps.<id> matches the producing step.
  2. Confirm the output key written to GITHUB_OUTPUT matches the one you reference.
  3. Add needs: so the consumer waits for the producer to finish.

How to prevent it

  • Always declare jobs.<id>.outputs to share values across jobs.
  • Keep step ids and output names consistent end to end.
  • Echo the value in the producer to confirm it is non-empty.

Related guides

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