GitHub Actions Composite Action Inputs Not Working: How to Fix It
Composite action inputs returning empty strings, secrets not passing through, or steps failing silently? Here are the exact fixes for common composite action bugs.
Composite actions are one of GitHub Actions' most useful features for DRY workflows, but they have several sharp edges around inputs, secrets, and environment variables that trip up even experienced engineers.
The Most Common Issue: Inputs Not Being Received
# .github/actions/deploy/action.yml
name: Deploy to EKS
inputs:
environment:
required: true
image_tag:
required: true
runs:
using: composite
steps:
- name: Deploy
run: echo "Deploying ${{ inputs.image_tag }} to ${{ inputs.environment }}"
shell: bash# workflow.yml - calling the composite action
- uses: ./.github/actions/deploy
with:
environment: production
image_tag: v1.2.3If inputs.image_tag shows up empty, check these:
Fix 1: Missing shell in Composite Action Steps
This is the #1 composite action bug. Every run step in a composite action must specify shell — it's not optional like in regular workflows.
# WRONG - will silently fail or use wrong shell
runs:
using: composite
steps:
- name: Deploy
run: echo "Deploying ${{ inputs.image_tag }}"
# Missing shell!
# CORRECT
runs:
using: composite
steps:
- name: Deploy
run: echo "Deploying ${{ inputs.image_tag }}"
shell: bash # REQUIRED in composite actionsFix 2: Secrets Cannot Be Passed as Inputs
This is the most confusing composite action limitation: you cannot directly pass secrets to composite action inputs via with:.
# WRONG - this doesn't work as expected
- uses: ./.github/actions/deploy
with:
aws_secret_key: ${{ secrets.AWS_SECRET_KEY }} # will be masked/emptyThe correct approach is to pass secrets as environment variables:
# CORRECT - use env at the step or job level
- uses: ./.github/actions/deploy
env:
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
with:
environment: production
image_tag: v1.2.3In your composite action, access them via ${{ env.AWS_SECRET_KEY }} or just $AWS_SECRET_KEY in shell.
Fix 3: Composite Action Can't Use secrets Context Directly
# WRONG - composite actions cannot use ${{ secrets.X }} directly
runs:
using: composite
steps:
- run: aws s3 cp file.txt s3://bucket/
env:
AWS_SECRET_KEY: ${{ secrets.MY_SECRET }} # This doesn't work in composite!
shell: bashComposite actions don't have access to the secrets context. The calling workflow must pass secrets through:
# In the composite action - receive via input
inputs:
aws_secret_key:
required: true
runs:
using: composite
steps:
- run: echo "Key length: ${#AWS_SECRET_KEY}"
env:
AWS_SECRET_KEY: ${{ inputs.aws_secret_key }}
shell: bash# In the calling workflow - pass the secret
- uses: ./.github/actions/deploy
with:
aws_secret_key: ${{ secrets.AWS_SECRET_KEY }} # Works as input from caller
environment: productionFix 4: Input Default Values Not Working
# This default value syntax is wrong
inputs:
replicas:
default: "3"
description: "Number of replicas"
runs:
using: composite
steps:
- run: kubectl scale deploy myapp --replicas=${{ inputs.replicas || 3 }}
shell: bashThe || fallback in composite actions doesn't work as expected because inputs.replicas always has a value (the default). Use the input directly:
- run: kubectl scale deploy myapp --replicas=${{ inputs.replicas }}
shell: bashIf you need dynamic defaults:
- name: Set replicas
id: config
run: |
REPLICAS="${{ inputs.replicas }}"
echo "replicas=${REPLICAS:-3}" >> $GITHUB_OUTPUT
shell: bash
- run: kubectl scale deploy myapp --replicas=${{ steps.config.outputs.replicas }}
shell: bashFix 5: Outputs Not Being Set Correctly
# composite action outputs
outputs:
image_digest:
description: "The digest of the pushed image"
value: ${{ steps.push.outputs.digest }}
runs:
using: composite
steps:
- name: Build and push
id: push
run: |
DIGEST=$(docker push myapp:latest | grep digest | awk '{print $3}')
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
shell: bashCommon mistake: forgetting id: on the step that sets the output. Without id: push, ${{ steps.push.outputs.digest }} returns empty.
Fix 6: Composite Action Not Found
Error: Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/repo/.github/actions/my-action'.
For local composite actions, the path must be relative to the repo root:
# WRONG
- uses: .github/actions/deploy # no leading dot-slash
# CORRECT
- uses: ./.github/actions/deploy # with dot-slashAlso verify the file is named exactly action.yml or action.yaml (not actions.yml).
Fix 7: if Conditions in Composite Steps
runs:
using: composite
steps:
- name: Deploy to prod
if: ${{ inputs.environment == 'production' }} # WRONG syntax in composite
run: ./deploy-prod.sh
shell: bash
# CORRECT - no ${{ }} around condition
- name: Deploy to prod
if: inputs.environment == 'production'
run: ./deploy-prod.sh
shell: bashIn composite action step conditions, don't wrap the expression in ${{ }}.
Debugging Composite Actions
# Add debug step to see all inputs
- name: Debug inputs
run: |
echo "environment: ${{ inputs.environment }}"
echo "image_tag: ${{ inputs.image_tag }}"
echo "ENV vars:"
env | grep -i deploy
shell: bashEnable debug logging by setting secret ACTIONS_STEP_DEBUG=true in your repository.
Summary Checklist
- Every
runstep hasshell: bash(orshell: pwsh) - Secrets passed via
env:notwith: - Step that sets output has an
id: - Local action path uses
./prefix -
if:conditions don't use${{ }}wrapper - Inputs accessed with
${{ inputs.name }}not${{ env.INPUT_NAME }}
Composite actions are worth the investment — a well-written deploy action can be reused across 20 workflows. Just watch out for these sharp edges.
Docs: GitHub Composite Actions
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
GitHub Actions Artifact Upload Failing — Size Limit & Permissions Fix
Your GitHub Actions artifact upload is failing with 'upload artifact failed' or size limit errors. Here are the exact causes and fixes for the most common artifact upload failures.
GitHub Actions Cache Not Working — How to Fix It
Your workflow runs are still slow even with actions/cache. Cache miss every time, cache key conflicts, wrong paths — here's how to diagnose and fix GitHub Actions caching.
GitHub Actions Docker Push: Permission Denied / Unauthorized Fix (2026)
Getting 'permission denied' or 'unauthorized: authentication required' when pushing Docker images in GitHub Actions? Here are all the causes and fixes.