criticalIntermediateUSE#runners#self-hosted#offline#jobs

Self-hosted runner offline - no jobs picked up

Workflow runs queued with 'Waiting for a runner to pick up this job'

Likely source:availabilityscaling

Focused incident mode — strips away everything but this runbook.

Symptoms

  • Workflow runs queued with 'Waiting for a runner to pick up this job'
  • Self-hosted runner shows as offline in Settings > Actions > Runners
  • Jobs stuck in queue for hours with no runner assigned

Self-hosted runners need outbound HTTPS to api.github.com and *.actions.githubusercontent.com. Verify firewall rules before restarting the service.

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Runner registration status

    gh api repos/<OWNER/REPO>/actions/runners --jq '.runners[] | {name, status, labels}'
  • Runner process on the host

    systemctl status actions.runner.<OWNER>.<REPO>.<RUNNER_NAME>.service

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • systemctl shows the service as inactive/dead
  • journalctl shows an unhandled exception or segfault

Confirm before fixing

ssh <RUNNER_HOST> systemctl is-active actions.runner.<OWNER>.<REPO>.<RUNNER_NAME>.service
READ

Check if the service is running

Fix

ssh <RUNNER_HOST> sudo systemctl start actions.runner.<OWNER>.<REPO>.<RUNNER_NAME>.service
CHANGE

Restart the runner service

Expected: Active: active (running)

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
gh api repos/<OWNER/REPO>/actions/runners --jq '.runners[] | {name, status}'
READ

Confirm which runners are offline

2
ssh <RUNNER_HOST> sudo systemctl restart actions.runner.<OWNER>.<REPO>.<RUNNER_NAME>.service
CHANGE

Restart the runner service

3
ssh <RUNNER_HOST> journalctl -u actions.runner.<OWNER>.<REPO>.<RUNNER_NAME>.service --since '5 min ago' --no-pager
READ

Verify the runner came back online

4
gh run list --limit 5
READ

Confirm queued jobs start executing

Prevention

  • Monitor runner heartbeat via the Actions API and alert on offline status > 5 minutes.
  • Use a process supervisor (systemd, supervisor) that auto-restarts the runner on crash.
  • Keep runner tokens rotated; use GitHub App tokens for long-lived self-hosted runners.
  • Run 'runnerctl diagnose' periodically to validate connectivity.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.