CI/CD

This job is stuck because you don't have any active runners

The job is queued and no runner will pick it up. Almost always tags, protected branches, or a runner that stopped reporting. How to tell which in a minute.

medium fix6 min read

the ci/cd error
This job is stuck because you don't have any active runners online or available with any of these tags assigned to them: docker

This job is stuck because the project doesn't have any runners online assigned to it.

This job is stuck because you don't have any active runners that can run this job.

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

  1. 1

    Read the tags in the message and compare against the runner

    grep -n "tags:" .gitlab-ci.yml

    The error names the exact tags the job asked for. A runner only takes a job when it carries every one of them, so a single typo or a tag nobody defined leaves the job queued forever.

  2. 2

    Check the runner is actually online

    sudo gitlab-runner verify --delete && sudo systemctl status gitlab-runner

    verify removes registrations GitLab no longer recognises. A runner that shows as online in the UI but never picks up work is usually a stale registration next to a dead process.

  3. 3

    Check whether the branch is protected and the runner is not

    git branch --show-current

    A protected runner only runs jobs on protected branches, and an unprotected runner is never offered a job from one. This is the cause whenever a pipeline works on feature branches and hangs on main.

All 9 sections

A stuck job means GitLab has the job queued and no runner has claimed it. The message usually names the reason, and it is worth reading precisely, because the three variants point at different problems.

Work through these in order. The first two account for most cases.

1. Tags

...any active runners online or available with any of these tags assigned to them: docker

A job with tags: is only offered to runners carrying every one of those tags. It is an exact string match, so docker and Docker are different tags.

build:
  tags:
    - docker        # a runner must have exactly this tag
  script:
    - make build

Compare against the runner in Settings → CI/CD → Runners. The tags are listed next to each runner.

There is a second half to this that catches people: a runner configured as "Run untagged jobs" off will not pick up a job with no tags: at all. So you can have a perfectly healthy runner and a job with no tags, and it still hangs. The setting is per-runner and defaults to off for newly registered runners in many setups.

Either add the tag to the runner, or align the job:

build:
  tags: [docker]     # match a tag the runner really has

Avoid removing tags to "fix" it if you have a heterogeneous fleet. Tags are how you keep a job that needs Docker off a shell runner.

2. Protected branches

This is the one that produces the most confusing symptom: pipelines work on feature branches and hang on main.

A runner marked protected only runs jobs from protected branches and tags. The inverse also holds: a job on a protected branch is never offered to an unprotected runner. Protected variables work the same way, which is the point of the feature, since it stops a fork or an unprotected branch reading production credentials.

Check Settings → CI/CD → Runners for the "Protected" flag, and Settings → Repository → Protected branches for which branches are protected.

If a deployment job to main is stuck and everything else works, this is nearly always why.

3. The runner is not actually online

The UI can show a runner that no longer exists.

sudo gitlab-runner verify --delete
sudo systemctl status gitlab-runner
sudo gitlab-runner --debug run          # foreground, shows why it is idle

verify --delete removes registrations GitLab no longer recognises, which clears up phantom entries. The debug run is the fastest way to see a runner that is alive but rejecting jobs, since it logs each check.

Check the runner's own view of the server:

sudo cat /etc/gitlab-runner/config.toml
concurrent = 4

[[runners]]
  name = "docker-runner-1"
  url = "https://gitlab.com/"
  executor = "docker"

concurrent = 1 with a long-running job already in flight looks exactly like "no runners available". Raising it is often the whole fix on a single self-hosted runner.

4. Shared runners are off, or you are out of minutes

On GitLab.com, shared runners require a verified payment method for new accounts, and free-tier compute minutes are finite. When they run out, jobs queue rather than failing with a clear message.

Check Settings → CI/CD → Runners for whether shared runners are enabled for the project, and the namespace usage page for remaining minutes. A group-level setting can disable shared runners for every project underneath it, which is easy to miss when you only look at the project.

5. Runner untagged and job tagged, in a group

A group runner has to be enabled for the project. Inherited availability is not automatic in every configuration, particularly where a group has "Enable shared runners for this group" turned off.

Reading it from the API

Faster than clicking through, and it shows the tags and status together:

curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/$PROJECT_ID/runners?scope=active" \
  | jq '.[] | {description, online, tag_list, is_shared}'
{ "description": "docker-runner-1", "online": true,
  "tag_list": ["docker","linux"], "is_shared": false }

Compare tag_list against the tags in the error message. That single comparison resolves the majority of these.

A quick diagnostic job

Drop this in temporarily to prove a runner will take anything at all:

runner-check:
  stage: .pre
  script:
    - echo "picked up by $CI_RUNNER_DESCRIPTION"
    - echo "tags: $CI_RUNNER_TAGS"
  rules:
    - when: always

If this runs and your real job does not, the difference is tags, protection, or a rule. If it also hangs, no runner is available to the project at all.

A checklist

  1. Read the tags named in the message.
  2. Settings → CI/CD → Runners. Compare tags exactly, including case.
  3. Job has no tags: → check the runner allows untagged jobs.
  4. Works on branches, hangs on main → protected runner and protected branch.
  5. gitlab-runner verify --delete and systemctl status gitlab-runner on the host.
  6. concurrent in config.toml may already be saturated.
  7. GitLab.com → shared runners enabled, and compute minutes remaining.
  8. Add a tagless .pre job to prove whether any runner will take work.

Frequently Asked Questions

Why is my GitLab job stuck with runners that are clearly online?

Almost always tags. A job with a tags: list is only offered to runners carrying every one of those tags, matched exactly, so Docker and docker are different. The mirror image catches people too: a runner with "Run untagged jobs" disabled will never pick up a job that has no tags: at all, so a healthy runner and a tagless job can sit staring at each other indefinitely. Compare the tags named in the error against the runner's tag list in Settings → CI/CD → Runners.

Why does my pipeline work on feature branches but hang on main?

A protected runner only accepts jobs from protected branches and tags, and jobs from a protected branch are only offered to protected runners. main is usually protected and feature branches are not, so the two halves of the fleet diverge exactly along that line. Check the Protected flag on the runner in Settings → CI/CD → Runners against Settings → Repository → Protected branches. The behaviour is deliberate: it is what stops an unprotected branch obtaining production credentials through protected variables.

How do I check whether a runner is genuinely online?

The UI can list registrations GitLab can no longer reach. On the runner host, sudo gitlab-runner verify --delete removes registrations the server no longer recognises, and sudo systemctl status gitlab-runner confirms the process is alive. For a runner that is up but never claims work, sudo gitlab-runner --debug run in the foreground logs each poll and is the quickest way to see why it is declining. Via the API, the online field on the project's runners endpoint gives the server's own view.

What does the concurrent setting in config.toml do?

It caps how many jobs a single runner process will execute at once, across all its registrations, and it defaults to 1. With one self-hosted runner and a long job already in progress, every other job queues, which produces a message about no runners being available even though the runner is healthy and working. Raise concurrent in /etc/gitlab-runner/config.toml and restart the runner. Size it against the CPU and memory on the host, since each concurrent job gets a full build environment.

Why did my jobs stop running on GitLab.com specifically?

The two usual causes are compute minutes and shared runner availability. Free-tier minutes are finite, and when a namespace exhausts them jobs queue rather than failing with an obvious message. New accounts also need a verified payment method before shared runners will run anything, which is an anti-abuse measure rather than a charge. Check the namespace usage page, and confirm shared runners are enabled for the project, remembering that a group-level setting can disable them for every project beneath it.

Reference and practice

Learn the underlying concept

Other CI/CD errors