Comprehensive toolkit for validating, linting, and testing GitHub Actions workflow files, custom local actions, and public actions. Use this skill when working with GitHub Actions YAML files (.github/workflows/*.yml), validating workflow syntax, testing workflow execution with act, or debugging workflow issues.
93
Does it follow best practices?
Validation for skill structure
This reference lists common errors encountered when working with GitHub Actions and how to fix them.
Error:
Error: Unable to process file command 'workflow' successfully.Common Causes:
Fix:
# Bad
name:My Workflow
jobs:
build:
runs-on: ubuntu-latest
# Good
name: My Workflow
jobs:
build:
runs-on: ubuntu-latestError:
Required property is missing: nameFix:
# Every workflow needs a name
name: CI Pipeline
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0Error:
The workflow is not valid. Unexpected value 'on'Fix:
# Bad - wrong event name
on:
pull-request: # Should be pull_request
# Good
on:
pull_request:
push:Error:
Unrecognized named-value: 'github'. Located at position 1 within expression: github.refFix:
# Bad - missing ${{ }}
if: github.ref == 'refs/heads/main'
# Good
if: ${{ github.ref == 'refs/heads/main' }}
# Even better (GitHub Actions auto-evaluates if conditions)
if: github.ref == 'refs/heads/main'Error:
Expected boolean value, got stringFix:
# Bad
if: ${{ 'true' }} # String, not boolean
# Good
if: ${{ true }}
if: ${{ success() }}
if: ${{ github.event_name == 'push' }}Warning:
Potential script injection via untrusted inputFix:
# Bad - vulnerable to injection
run: echo ${{ github.event.issue.title }}
# Good - use environment variables
env:
TITLE: ${{ github.event.issue.title }}
run: echo "$TITLE"Error:
Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/_actions/actions/chekout/v4'Common Causes:
Fix:
# Bad
- uses: actions/chekout@v4 # Typo
# Good
- uses: actions/checkout@v4Error:
Input required and not supplied: pathFix:
# Bad
- uses: some-action@v1
# Good
- uses: some-action@v1
with:
path: ./my-pathError:
Unexpected input 'invalid_input'Fix:
# Check the action's documentation for valid inputs
- uses: actions/checkout@v4
with:
# Only use documented inputs
ref: main
# Remove undocumented inputsWarning:
Node.js 12/16 actions are deprecatedFix:
# Deprecated - Node.js 12 (EOL April 2022)
- uses: actions/checkout@v2
# Deprecated - Node.js 16 (EOL September 2023)
- uses: actions/checkout@v3
# Older - Node.js 20 (EOL April 2026)
- uses: actions/checkout@v4
- uses: actions/checkout@v5
# Current - Node.js 20+/24 (v6)
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
# Note: Node.js 20 EOL is April 2026, Node.js 22 and 24 are currentError:
Unable to locate executable file: ubuntu-lastestFix:
# Bad
runs-on: ubuntu-lastest # Typo
# Good
runs-on: ubuntu-latestValid runner labels:
ubuntu-latest, ubuntu-22.04, ubuntu-20.04windows-latest, windows-2025, windows-2022, windows-2019macos-latest (now macOS 15), macos-15, macos-14, macos-26 (preview)macos-13 (RETIRED November 14, 2025 - no longer available)macos-15-intel, macos-15-large (Intel x86_64, long-term deprecated)macos-15-xlarge, macos-14-xlarge (M2 Pro with GPU)gpu-t4-4-core (GPU runners for ML/AI)Error:
Job 'deploy' depends on job 'biuld' which does not existFix:
# Bad
jobs:
build:
runs-on: ubuntu-latest
deploy:
needs: biuld # Typo
# Good
jobs:
build:
runs-on: ubuntu-latest
deploy:
needs: buildError:
Circular dependency detectedFix:
# Bad
jobs:
job1:
needs: job2
job2:
needs: job1 # Circular!
# Good
jobs:
job1:
runs-on: ubuntu-latest
job2:
needs: job1Error:
Invalid CRON expression: '0 0 * * 8'Fix:
# Bad
schedule:
- cron: '0 0 * * 8' # Day 8 doesn't exist
# Good
schedule:
- cron: '0 0 * * 0' # Sunday
# CRON format: minute hour day month weekday
# Minute: 0-59
# Hour: 0-23
# Day: 1-31
# Month: 1-12
# Weekday: 0-6 (0 = Sunday)# Correct way to define multiple schedules
on:
schedule:
- cron: '0 0 * * 1' # Monday at midnight
- cron: '0 12 * * 5' # Friday at noonError:
Invalid glob pattern: '**.js'Fix:
# Bad
on:
push:
paths:
- '**.js' # Missing directory separator
# Good
on:
push:
paths:
- '**/*.js'
- 'src/**'Error:
Secret MY_SECRET not foundFix:
# Use secrets correctly
env:
API_KEY: ${{ secrets.MY_SECRET }} # Must match name in settingsCommon Issue:
# Bad - environment variable not accessible
steps:
- run: echo $MY_VAR # May not work on Windows
# Good - use env
steps:
- name: Print variable
env:
MY_VAR: ${{ secrets.MY_SECRET }}
run: echo "$MY_VAR" # Unix
# or
run: echo $env:MY_VAR # Windows PowerShellError:
Matrix configuration is invalidFix:
# Bad
strategy:
matrix:
os: ubuntu-latest # Should be an array
# Good
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [20, 22, 24] # Node 16 EOL Sep 2023, Node 20 EOL Apr 2026# Correct way to reference matrix variables
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
jobs:
test:
runs-on: ${{ matrix.os }}# Understanding conditions
steps:
- name: Run on success (default)
run: echo "Runs only if previous steps succeeded"
- name: Run always
if: always()
run: echo "Runs whether previous steps succeeded or failed"
- name: Run on failure
if: failure()
run: echo "Runs only if a previous step failed"
- name: Run on success
if: success()
run: echo "Runs only if all previous steps succeeded"Set secrets in repository settings:
ACTIONS_STEP_DEBUG = true (detailed step logs)ACTIONS_RUNNER_DEBUG = true (runner diagnostic logs)steps:
- name: Setup tmate session
if: failure()
uses: mxschmitt/action-tmate@v3steps:
- name: Dump GitHub context
run: echo '${{ toJSON(github) }}'
- name: Dump job context
run: echo '${{ toJSON(job) }}'
- name: Dump runner context
run: echo '${{ toJSON(runner) }}'actions/checkout@v6 not actions/checkout@mainname: "My: Workflow"timeout-minutes# Example of good practices
name: Production Deployment
on:
push:
branches: [main]
concurrency:
group: production
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
run: |
./deploy.shInstall with Tessl CLI
npx tessl i pantheon-ai/github-actions-validator@0.1.1