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.
Overall
score
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.0