Jobs Queuing or Stuck in "Not Running" / "Preparing" State

Overview

When a job sits in a "Not Running""Queued", or prolonged "Preparing Environment" state, it almost always means your organization has reached a concurrency limit. This article explains what concurrency limits apply to your plan, how to identify what is consuming your concurrency, and how to resolve the issue.

Understanding Concurrency Limits by Plan

Every CircleCI plan has a maximum number of jobs that can run simultaneously. When that limit is reached, new jobs wait in the queue.

PlanConcurrent Job LimitSymptom
Free30 jobsJob shows "Not Running"
Performance80 jobsJob shows "Not Running"
Scale / CustomConfigurable (default 200)Job stays in "Preparing Environment" for >5 minutes

Self-hosted runners have a separate limit. The maxConcurrentTasks setting on your runner resource class caps how many jobs a runner will claim simultaneously, independent of your plan's job concurrency. See Step 5 below.

Step 1: Check Your Current Concurrency Usage

There is no real-time concurrency view in the CircleCI UI, but you have two options:

Option A — Concurrency Snapshot Script (Cloud only)

Use the Current Concurrency Snapshot script to get a point-in-time view of all running jobs in your org and which resource classes they are using. Run it while jobs are queuing to see what is consuming capacity.

Option B — CircleCI API

Query the running workflows across your org using the CircleCI v2 API with a personal API token:

curl -G "https://circleci.com/api/v1.1/recent-builds?shallow=true&limit=100" \

-H "Circle-Token: <YOUR_API_TOKEN>" | jq '.[] | select(.status == "running") | {build_url, queued_at, build_num}'

Step 2: Check for Forgotten SSH Jobs (Most Common Cause)

SSH jobs are the #1 hidden cause of concurrency exhaustion. Once you navigate away from a running SSH job, it disappears from the pipeline view — but it is still running and consuming a concurrency slot.

  • An SSH job stays available to connect for 10 minutes after it finishes.
  • Once you connect, the session stays open for up to 2 hours.
  • During all of that time, the job counts against your concurrency limit.

How to find and cancel SSH jobs:

Navigate to the legacy jobs view for each project where SSH reruns may have been triggered:

https://app.circleci.com/pipelines/{vcs}/{org}/{project}/jobs

Replace {vcs} with gh or bb, and fill in {org} and {project}.

SSH jobs will be visible here even when they don't appear in the pipelines view. Click into any running SSH job and cancel it from the Rerun menu.

You can also find all running SSH jobs across your org via the API:

curl -G "https://circleci.com/api/v1.1/recent-builds?shallow=true" \

-H "Circle-Token: <YOUR_API_TOKEN>" | jq '.[] | select(.why == "ssh") | select(.status == "running") | {build_url, build_num}'

Prevention: Always manually cancel an SSH job when you finish debugging. Go to Project Settings → SSH → Disable rerun with SSH if SSH reruns are not needed for a project.

Step 3: Check for Invalid or Misconfigured Runner Resource Classes

If your configuration references a runner resource class that has no active runners attached to it — due to a typo, a decommissioned machine, or a runner that hasn't checked in — jobs will queue against that resource class indefinitely. Those queued jobs count toward your concurrency limit, causing other jobs to queue even though nothing appears to be running.

How to check:

  1. Go to Org Settings → Self-Hosted Runners and inspect the inventory for each resource class referenced in your config.yml.
  2. Any resource class showing "No Runners" or "No Tasks" is a candidate.
  3. Verify the resource class name in your config exactly matches the name in the runner inventory (names are case-sensitive).
# Example — verify this matches exactly in the runner inventory

resource_class: my-org/my-runner-name

Cancel any jobs queued against invalid resource classes to immediately free up concurrency.

Step 4: Check for Unexpectedly High Parallelism

A single job configured with a high parallelism value can consume a large portion of your concurrency budget instantly. A common typo — for example, parallelism: 99 instead of parallelism: 9 — can spike usage and queue everything else.

How to check:

Search your config.yml files across all active projects for the parallelism key:

# Each parallel "slice" counts as one concurrent job against your limit

parallelism: 9 # 9 concurrent jobs — intended

parallelism: 99 # 99 concurrent jobs — likely a typo

Also review any scheduled pipelines and automations. If multiple scheduled triggers fire at the same time (for example, a burst of delayed VCS webhooks), they can all start high-parallelism jobs simultaneously.

Step 5: Self-Hosted Runner — maxConcurrentTasks Limit

If you are using self-hosted runners (machine or container runner), concurrency is also controlled by the maxConcurrentTasks setting on the resource class, independent of your plan's job limit. If this is set too low, jobs will queue at the runner level even if your plan limit has not been reached.

The default is 20 concurrent tasks for most plans. Check your plan's runner inventory page:

https://app.circleci.com/runners/{vcs}/{org}/inventory

If you are seeing queued jobs but your plan's concurrency limit is not the constraint, the runner's maxConcurrentTasks cap is likely the bottleneck. Contact support to request an increase.

Step 6: Request a Concurrency Limit Increase

If you have ruled out the causes above and are legitimately hitting your plan's job concurrency ceiling, you can request an increase:

  • Scale and Custom plan customers: Contact CircleCI support and include the output from the Concurrency Snapshot Script and a description of your typical pipeline patterns. We can increase your concurrency limit.
  • Performance plan customers: Performance plans have a fixed 80-job limit. To go beyond this, you will need to upgrade to a Scale or Custom plan. Contact your account team or CircleCI Sales.
  • Free plan customers: Free plans are capped at 30 jobs. Upgrading to Performance or Scale is the path to higher concurrency.

Preventing Future Queuing

ActionImpact
Cancel SSH jobs immediately after debuggingFrees 1–2 hours of concurrency per job
Set explicit parallelism values; review regularlyPrevents runaway parallelism from a typo
Stagger scheduled pipelinesAvoids burst triggers that simultaneously consume concurrency
Use the Concurrency Snapshot during peak hoursGives early warning before limits are hit
Audit runner inventory after decommissioning machinesPrevents ghost resource classes from counting against limits

Additional Resources

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Article is closed for comments.