Skip to content
Latchkey

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.

.github/workflows/ci.yml
# 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 list

Common 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.

.github/workflows/ci.yml
# 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

  1. List the actual labels on your runners and request only labels that coexist on one runner.
  2. Use the group object form when access is managed by runner group.
  3. 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.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →