Overview
When several pipelines share the same serial-group, CircleCI skips jobs from older pipelines if a newer pipeline already holds (or is waiting for) that group’s lock. Those skipped jobs finish as not_run, not as failed.
This may cause discrepancies if you expect a set of jobs to have been executed on success. If you gate CD on pipeline or workflow status alone, a preempted run can look like “CI passed” when the protected job never executed.
Why this happens
Serial groups use a shared lock keyed by your serial-group value. When an older pipeline reaches the serial-group start step while a newer pipeline holds or is waiting for the lock, the older job is rejected and marked not_run.
Skipped jobs are removed from the queue — they do not wait and resume later.
Priority follows pipeline number (higher = newer = takes precedence).
not_runis a job-level status. There is no separate workflow status that means “preempted by serial group.”
Solution: fail the workflow when the job is not_run
The following example configuration file added a workflow fail-if-smoke-not-run which will cause the pipeline to report a failure state in the event the smoke-tests job does not run.
jobs:
smoke-tests:
docker:
- image: cimg/base:stable
steps:
- run: ./run-smoke-tests.sh
fail-if-smoke-not-run:
docker:
- image: cimg/base:stable
steps:
- run:
name: Smoke tests did not run (serial group preempted)
command: |
echo "smoke-tests was skipped (not_run) — likely preempted by a newer pipeline in the same serial group."
exit 1
workflows:
deploy:
jobs:
- build
- smoke-tests:
serial-group: << pipeline.project.slug >>/smoke-tests
requires:
- build
- fail-if-smoke-not-run:
requires:
- smoke-tests: not_run
This allows you to gate your CD behind the success/failure state of the pipeline. Repeat for each critical serial-group job. Match branch/tag filters on the gate to the serial-group job.
