Documented limitations
This is a YAML subset parser. Anchors and aliases, tags, and document markers are unsupported. It does not check full YAML support, action existence, action input parameters, network validation, or complete cron semantics.
Browser-local checker
Paste a .github/workflows/*.yml file into this GitHub Actions workflow validator to check its supported YAML syntax, then review selected workflow structure errors and warnings in your browser.
YAML syntax result
Checking…Issue summary
0 errors, 0 warningsThis is a YAML subset parser. Anchors and aliases, tags, and document markers are unsupported. It does not check full YAML support, action existence, action input parameters, network validation, or complete cron semantics.
Common hosted runners include ubuntu-latest, windows-latest, and macos-latest. Common events are push, pull_request, workflow_dispatch, and schedule.
Use least-privilege permissions: contents: read, protect secrets.GITHUB_TOKEN, use a concurrency group to prevent duplicate runs, and use matrix strategy for variants.
Your workflow text is parsed and checked in this browser. There is no network validation and no GitHub API verification.
The page starts with a clean example containing push and workflow_dispatch triggers, two jobs, a needs dependency, a matrix strategy, permissions: {contents: read}, and actions/checkout@v4. Select Restore example to load the example again.
The dependency-free parser supports this documented YAML subset:
|>[push, workflow_dispatch] and {contents: read}Syntax failures stop structural checks and report a concrete reason with a one-based line and column. Diagnostics can identify inconsistent indentation, tabs used for indentation, a missing mapping colon, a missing mapping value, an unclosed quote, an unclosed flow collection, or malformed flow syntax. Literal blocks retain line breaks; folded blocks join supported content lines with spaces.
Anchors and aliases, tags, and document markers such as --- are unsupported features. The parser reports these explicitly rather than silently treating them as valid YAML.
After syntax parsing succeeds, the validator checks:
on trigger is present.jobs mapping exists and is not empty.runs-on, unless it uses a reusable workflow through uses.steps sequence.uses or run; both or neither produce an error.needs reference names an existing job ID. Unknown references list the available job IDs.on.schedule cron value contains exactly five whitespace-separated fields.0–59, hour 0–23, day of month 1–31, month 1–12, and day of week 0–6. A complete * field and the implemented stepped wildcard form such as */15 are accepted.uses reference without an @ref produces a warning about supply-chain ambiguity. Local paths, Docker references, and actions/* references are excluded from this warning.${{ expressions have a closing }} delimiter. This is closure detection only.name, run-name, on, permissions, env, defaults, concurrency, and jobs.Diagnostics show error or warning severity. A clean workflow explicitly shows No errors found and 0 errors, 0 warnings; the result area does not remain blank.
The parser normalizes carriage returns to line feeds, removes blank lines and comments outside quoted strings, and reads the document with a line cursor. At each block level, the first child indentation establishes the expected indentation for sibling entries. A different indentation is reported as an indentation problem instead of being silently reinterpreted.
For each schedule value, the validator performs the actual operation:
fields = cron.trim().split(/\s+/)
The result must contain exactly five fields in this order: minute, hour, day of month, month, and day of week. Each field must use the implemented basic character form containing digits, commas, asterisks, slashes, and hyphens. The exact token * is recognized as a symbolic wildcard before numeric atom checks. Numeric atoms are then compared with the inclusive ranges listed above. This is a basic field check: it does not calculate a next run or validate complete cron grammar, calendar combinations, time zones, or daylight-saving behavior.
For expressions, the validator scans scalar text from left to right. When it finds ${{, it searches for the next }}. If no closing delimiter exists, it reports expression is unclosed at the opening delimiter. It does not evaluate expression syntax or values.
The issue summary counts emitted diagnostics:
summary = `${errors} errors, ${warnings} warnings`
The pass state is based on the error count. Warnings remain visible when there are no errors.
runs-on selects a runner label such as ubuntu-latest, windows-latest, or macos-latest. Common trigger names include push, pull_request, workflow_dispatch, and schedule.
A minimal permission example is permissions: {contents: read}. Workflows may also use secrets.GITHUB_TOKEN, a concurrency group to prevent duplicate runs, and a strategy.matrix value to run job variants. The page displays these terms in its example or guidance; it does not verify secret availability, runner availability, or remote action behavior.
This is a dependency-free YAML subset parser, not a full YAML implementation and not a complete GitHub Actions validator. It does not implement every YAML scalar, flow, quoting, or block-scalar option. Anchors and aliases using & or *, tags beginning with !, and document markers such as --- are unsupported and produce explicit diagnostics.
The validator does not make network requests, execute workflows, verify that an action exists, inspect action input parameters, validate the GitHub API, evaluate expressions, or provide complete cron semantics. An @ref warning checks only whether a reference is present; it does not prove that the ref is immutable or safe.
It checks the supported YAML subset and selected workflow rules, including required on and jobs, job runners and steps, needs IDs, basic five-field schedules, action reference warnings, unclosed expressions, and unknown top-level keys.
0 3 * * * a valid GitHub Actions schedule?The tool's basic checker accepts 0 3 * * *. It recognizes each bare * as a wildcard and reports no cron errors when the surrounding workflow is otherwise valid.
*/15 * * * *?Yes. The implemented basic cron checker accepts stepped wildcards such as */15 and checks the resulting numeric atoms and field count.
No. It checks five fields, supported characters, and basic numeric ranges. It does not simulate calendars, calculate the next run, handle time zones or daylight-saving behavior, or verify GitHub's actual scheduler.
Quoting keeps cron punctuation such as * as a YAML scalar in the workflow document. The validator checks the parsed schedule value and does not require one particular quoting style.
No. Parsing and checks run in the browser. The tool does not contact GitHub to confirm action existence, validate action input parameters, or perform network verification.
60 24 0 13 7?The numeric boundary checks remain strict. The validator reports out-of-range errors for minute and hour, along with the corresponding invalid day-of-month, month, and day-of-week values.
A regular job requires runs-on and a non-empty steps sequence. A job with a reusable workflow uses reference is exempt from those two checks.