Waiting for a Runner to Pick Up This Job: Fixes
Last updated
Waiting for a runner to pick up this job means your job is queued and no runner has accepted it yet. For GitHub-hosted runners it is usually a concurrency limit or a short capacity delay; for self-hosted runners it is almost always a runs-on label that matches no online runner. This page covers both, with the limits from GitHub's usage limits page, checked October 2026.
The exact message
Waiting for a runner to pick up this job...
You see it at the top of a queued job's log, and the job shows a yellow "Queued" status. Some self-hosted setups show Requested labels: self-hosted, linux, gpu and Job defined at: ... with Waiting for a runner to pick up this job..., which helps you spot the mismatch.
Cause 1: self-hosted runner labels do not match
If you use runs-on: [self-hosted, linux, x64], a runner must be online and have every one of those labels. Typos and missing labels are the top cause. Check:
- Settings, then Actions, then Runners: is the runner Online and Idle?
- Do its labels include everything in
runs-on? Every label must be present on the same runner. - Is the runner in the right runner group, and does that group allow your repository?
- Is the runner service running on the host (
systemctl status actions.runner.*)?
jobs:
build:
runs-on: [self-hosted, linux, x64]
Job queue time on self-hosted runners is limited to 24 hours; after that the job is cancelled automatically, per the limits page.
Cause 2: you hit the concurrency limit
GitHub caps how many jobs run at once. Extra jobs queue until a slot frees. Figures for standard GitHub-hosted runners:
| Plan | Concurrent jobs | macOS |
|---|---|---|
| Free | 20 | 5 |
| Pro | 40 | 5 |
| Team | 60 | 5 |
| Enterprise | 500 | 50 |
Larger runners have their own limits: Team and Enterprise plans can run up to 1,000 concurrent jobs in total, and per-runner concurrency varies by type. A matrix with 30 cells on a Free plan will run 20 and queue 10. Matrix size, many PRs pushing at once, and scheduled workflows at the top of the hour all add up. See matrix builds for max-parallel and the matrix expander to count your cells.
Fix: reduce parallel jobs, cancel superseded runs, or add capacity.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
This cancels older runs of the same branch when a new push arrives, which frees slots (read The operation was canceled before enabling it on deploy workflows).
Cause 3: the job is waiting for a larger runner
A larger runner (named with a custom label) queues when its own maximum is reached or when auto-scaling has not provisioned machines yet. Check the runner's maximum concurrency and increase it in the runner's settings if the plan allows.
Cause 4: a short capacity or incident delay
Occasionally hosted runners of a given type are slow to start. If many unrelated jobs are queued across repositories, check the GitHub status page and wait. Do not cancel and re-run in a loop, because each re-run goes to the back of the queue.
Cause 5: wrong runs-on label for hosted runners
A label that does not exist (for example ubuntu-24 instead of ubuntu-24.04, or a retired image) leaves the job queued with no runner to pick it up. Use a label from the hosted runner list. The YAML checker catches obvious typos.
Cause 6: billing or policy blocks
If the account has hit a spending limit, the job fails instead of queueing, with a different message. Organisation policy can also restrict which runners a repository may use.
How to diagnose quickly
gh run list --status queued --limit 20
gh api repos/OWNER/REPO/actions/runners --jq '.runners[] | {name, status, busy, labels: [.labels[].name]}'
If runners show online and busy: false but your job still waits, labels or groups do not match. If every runner is busy: true, you need more capacity.
Remove queue time for good
Queue time is wasted money for developers waiting on feedback. You can add self-hosted runners (and own the scaling), pay for GitHub larger runners, or use a runner provider that supplies machines on demand. compiler.dev starts a fresh 8 vCPU / 16 GB VM per job and runs your existing jobs after you change one line to runs-on: [self-hosted, Linux, compiler-ci], so concurrency is not capped by your GitHub plan tier. See pricing and self-hosted vs GitHub-hosted runners.
How to prevent it
- Use
concurrencywithcancel-in-progresson pull request workflows. - Keep matrix sizes within your plan's concurrency, or set
max-parallel. - Stagger cron schedules instead of using
0 * * * *for everything (the cron builder helps). - Monitor self-hosted runners and alert when none are online.
- Keep runner labels in one documented place.
FAQ
How long can a job wait for a runner?
For self-hosted runners, 24 hours, then GitHub cancels the job. Hosted jobs normally start within seconds to minutes unless you are at your concurrency limit.
Why is my job queued when no other jobs are running?
For self-hosted runners, the labels or runner group do not match, or no runner is online. For hosted runners, check the label and the status page.
Do queued jobs cost money?
Queued time is not billed. Billing starts when a runner starts running the job.
Can I raise the concurrency limit?
Limits depend on plan. Larger plans have higher limits, and larger runners have separate limits. Contact GitHub Support for plan-specific increases.
Related
- API Rate Limit Exceeded in GitHub Actions: FixesFix "API rate limit exceeded for installation ID" in GitHub Actions: GITHUB_TOKEN allows 1,000 requests per hour per repo. Secondary limits and fixes.
- Cache Not Found for Input Keys: Causes and FixesCache not found for input keys in GitHub Actions is a cache miss, not always an error. Why it happens, how key and branch scope work, and fixes.
- Docker Pull Rate Limit in GitHub Actions: FixesFix "toomanyrequests: You have reached your pull rate limit" in GitHub Actions: Docker Hub limits, docker/login-action, mirrors and GHCR alternatives.
- Hosted Runner Lost Communication With the ServerFix "The hosted runner lost communication with the server" in GitHub Actions: causes like OOM, disk full and killed processes, with steps to diagnose.