actionlint: Lint GitHub Actions Workflows
actionlint validates GitHub Actions workflow files, catching bad syntax, undefined expression contexts, and ShellCheck issues in run steps before they fail a real run.
Workflow bugs are slow to find because you have to push to test them. actionlint checks the YAML locally and in CI in a fraction of a second.
What it does
actionlint scans .github/workflows automatically (or the files you name), validating workflow schema, ${{ }} expression types, runner labels, action input names, and shell inside run: via ShellCheck. It exits 1 when it finds problems, 0 when clean.
Common usage
# auto-discover and lint all workflows
actionlint
# lint a specific file with a chosen format
actionlint -format '{{json .}}' .github/workflows/ci.yml
# run via the official Docker image
docker run --rm -v "$PWD":/repo -w /repo rhysd/actionlintFlags
| Flag | What it does |
|---|---|
| (no args) | Lint every workflow under .github/workflows |
| -format <tmpl> | Go-template output (e.g. JSON for tooling) |
| -shellcheck <path> | Path to shellcheck (empty string disables it) |
| -pyflakes <path> | Path to pyflakes for python run steps |
| -ignore <regex> | Suppress errors matching a pattern |
| -color | Force colored output |
In CI
actionlint needs shellcheck on PATH to lint run-step shell; the official Docker image bundles it. To skip shellcheck (for example on a minimal runner), pass -shellcheck= with an empty value rather than letting it error.
Common errors in CI
"label \"ubuntu-latest-8core\" is unknown" means a self-hosted or custom runner label actionlint does not know; declare it in actionlint.yaml. "property \"foo\" is not defined in object type" flags a typo in a context like steps or env. "could not parse as YAML" means the workflow file itself is malformed.