GitHub Actions Composite Action Outputs Empty in the Caller
A composite action runs fine but its output is empty in the calling workflow. Composite outputs must be declared under outputs: in action.yml and bound to an inner step’s output via the steps context.
What this error means
A workflow reads steps.<action-id>.outputs.<name> after calling a local composite action and gets an empty string, even though the inner step wrote to GITHUB_OUTPUT.
# caller
- id: setup
uses: ./.github/actions/setup
- run: echo "${{ steps.setup.outputs.version }}" # emptyCommon causes
Output not declared in action.yml
A composite action only exposes outputs listed under outputs:. Writing to GITHUB_OUTPUT inside a step is not enough; the action must map it out.
Wrong binding expression
The output value must reference the inner step via the steps context, e.g. value: ${{ steps.<inner>.outputs.<name> }}, with an inner step id that matches.
How to fix it
Declare and bind the output in action.yml
Map each composite output from the inner step that produced it.
# .github/actions/setup/action.yml
outputs:
version:
value: ${{ steps.v.outputs.version }}
runs:
using: composite
steps:
- id: v
shell: bash
run: echo "version=1.2.3" >> "$GITHUB_OUTPUT"Verify the names line up end to end
- Confirm the inner step id in the outputs binding matches the producing step.
- Confirm the output key written to GITHUB_OUTPUT matches the declared name.
- Read it in the caller via the action’s step id: steps.<action-id>.outputs.<name>.
How to prevent it
- Always declare composite outputs under outputs: with a steps-context binding.
- Keep inner step ids and output names consistent.
- Echo the value inside the action to confirm it is non-empty before mapping.