Skip to content
Latchkey

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

Terminal
# 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/actionlint

Flags

FlagWhat 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
-colorForce 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.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →