- Issues
- ISSUE-423
Workflow file is not valid
Control:CTRL-423Workflow files must be valid
📋 What is this?
A file under .github/workflows cannot be parsed as a workflow: an undefined YAML anchor, a duplicate key, a tab-indented block, a syntax error. GitHub shows such a file as an invalid workflow on the Actions tab and does not run it.
- One finding per file, with the parser's own message (
unknown anchor 'checkout_with' referenced,line 7: mapping key "runs-on" already defined). - The other workflow files of the repository are analyzed and scored as usual. When every file is invalid there is nothing left to analyze: the controls that read the workflows show as not evaluated rather than passed, and only this finding and repository-level controls such as branch protection report a result. A file that could not be read or fetched is reported separately, as a collection problem, not as this finding.
- An empty file, or a file with no
jobs:block, is not flagged, although GitHub may still refuse it. - Only a YAML parse failure is reported. A file that is well-formed YAML but that GitHub still rejects is not flagged: a job without
runs-on, an unterminated${{ }}expression, aneeds:naming a job that does not exist. The Actions tab, or a linter such as actionlint, reports those.
⚠️ Impact
Whatever that workflow was meant to do, a test suite, a security scan, a release gate, never happens, and nothing else in the repository notices: the file sits in .github/workflows looking like coverage it does not provide.
🔧 How to fix
Open the Actions tab and read the error GitHub reports for the file, then fix it. For an undefined anchor, define it in the same file before using it or inline the block: GitHub Actions resolves YAML anchors within one file only, and never merge keys. Confirm the workflow appears without the invalid-workflow banner once fixed.
# .github/workflows/anchor-aliases.yml: ❌ the alias has no anchor in this filename: Anchor Aliaseson: [push]jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7 with: *checkout_with test: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7 with: *checkout_with# .github/workflows/anchor-aliases.yml: ✅ the anchor is defined before it is usedname: Anchor Aliaseson: [push]jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7 with: &checkout_with persist-credentials: false fetch-depth: 0 test: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.1.7 with: *checkout_with💡 Tips
- A duplicate key (
on:twice, orruns-on:twice in one job) is refused too, even though many YAML parsers silently keep the last value. Keys are compared ignoring case, as GitHub does:on:next toON:, orFOOnext tofoounderenv:, is a duplicate. - A YAML merge key (
<<: *anchor) is not flagged: Plumber's parser resolves it, but GitHub Actions does not, so such a file can pass this control and still be refused by GitHub. - With the control turned off, or absent from a full configuration without
extends, the control shows as skipped and an invalid file degrades the run instead: the report says it could not be parsed and the score is withheld until it is fixed or the control is enabled.
⚙️ Configure this control
With the CLI alone: set it in your configuration file. Every field and default is in the controls configuration reference, CTRL-423.