Fix GitHub Actions Unexpected Value: runs-on
Resumo
Pixel’s announcement explains why GitHub Actions reports an unexpected value for runs-on, even when indentation looks correct. It covers reusable workflow caller jobs, which cannot set a runner, and defaults mappings, which accept only run, helping the community diagnose and fix workflow validation errors.
DEV Community
GitHub Actions unexpected value runs-on on a job that cannot have one
GitHub Actions unexpected value runs-on means the validator was reading a mapping whose allowed keys do not include runs-on when it reached yours. The mapping is rarely the workflow root and the indentation is usually right: far more often the job had already been decided to be a reusable-workflow caller, and a caller job is a different shape with a different set of keys. The two key lists are read from the job-factory and workflow-job definitions in the shipped workflow-v1.0.json. The log line is quoted from aureliojargas/github-actions-sandbox#2. What this error means The workflow does not start and the report names a runs-on: line that looks perfectly ordinary. Check what else is in that job before you check the indentation. A job containing uses: is a caller job, and a caller job accepts name, uses, with, secrets, needs, if, permissions, concurrency and strategy, and nothing else; runs-on is not on that list, because the machine is chosen inside the workflow being called. The other place the key is refused is the workflow-level defaults: mapping, which accepts only run. Both read as an indentation problem and neither is one. ```Actions log, quoted from aureliojargas/github-actions-sandbox#2 The workflow is not valid. .github/workflows/defaults.yml (Line: 3, Col: 3): Unexpected value 'runs-on' .github/workflows/defaults.yml (Line: 6, Col: 5): Required property is missing: runs-on
Common causes
The job calls a reusable workflow, so it cannot choose a runner
The largest cause and the one that looks least like a mistake. A job with uses: is a caller, and the caller shape has no runs-on. Whoever added the line was usually trying to move that work onto a different runner, which is a legitimate goal that this key cannot serve.
runs-on was placed under defaults, at the workflow or job level
The defaults mapping accepts only run, and run accepts only shell and working-directory. Setting a default runner for every job is not something the schema supports, so the attempt is rejected and the job that needed the key is then reported as missing it.
Another caller-only or job-only key appeared first
Because narrowing happens key by key, the reported key is the second conflicting one rather than the wrong one. A job with environment above uses gets a complaint about uses; one with uses above environment gets a complaint about environment. In our experience this is what makes the reports feel arbitrary.
A de-indent moved the key out of its job
The classic explanation, and still real. It is distinguishable at a glance from the column number in the report: the workflow root is column 1, and a key inside a job sits at the same column as its siblings.
How to fix it
Look at the job body before the indentation
- Open the line the report names and read the whole job it belongs to.
- If the job has a
uses:key, it is a caller job andruns-onhas to go. - If the line is under
defaults:, it is in a mapping that accepts onlyrun. - Only if neither is true, check the column number and compare it against the job's other keys.
Pass the runner through the called workflow as an input
Where the caller genuinely needs different hardware, declare an input on the called workflow and use it in that workflow's own runs-on. This is the supported route and it keeps the choice with the job that actually runs.
```.github/workflows/build.yml (illustrative)
on:
workflow_call:
inputs:
runner:
type: string
default: ubuntu-latest
jobs:
build:
runs-on: ${{ inputs.runner }}
steps:
- uses: actions/checkout@v5
Put runner defaults somewhere the schema supports Since defaults cannot carry a runner, use the mechanisms that can. A workflow-level env entry referenced from each job's runs-on keeps one place to edit, and a matrix does the same for a set of jobs. ```.github/workflows/ci.yml (illustrative) env: RUNNER_LABEL: ubuntu-latest jobs: t...

Powered by Readybot.io