GitHub Actions runs-on Array vs Group Object - Job Never Matches
A job never matches a runner because runs-on was written in the wrong shape. A list of labels requires a runner carrying every label; targeting a runner group needs the object form with group and optional labels.
What this error means
A job queues forever or fails to match, because the runs-on label array demanded a combination no runner has, or because a runner-group selection was written as a flat list.
# array: requires a runner with ALL of these labels
runs-on: [self-hosted, linux, gpu, big] # no single runner has all four
# group selection needs the object form, not a flat listCommon causes
Label array ANDs every label
A runs-on list matches only a runner that carries all listed labels. Adding labels narrows the match; an over-specified list matches nothing.
Runner group selection needs the object form
To target a runner group you use runs-on with a group: (and optionally labels:) key. Writing the group name as a bare list label does not select the group.
How to fix it
Use the form that matches your intent
Use a label list only for labels a single runner truly has; use the object form to pick a runner group.
# match by labels on one runner
runs-on: [self-hosted, linux, x64]
# match by runner group + label
runs-on:
group: ubuntu-runners
labels: [self-hosted, gpu]Confirm runner capabilities
- List the actual labels on your runners and request only labels that coexist on one runner.
- Use the group object form when access is managed by runner group.
- Validate runs-on with actionlint, which knows valid label/group shapes.
How to prevent it
- Only AND labels that a single runner actually carries.
- Use the runs-on object form for runner-group targeting.
- Keep a documented map of runner labels and groups.