GitLab CI: `rules`, `workflow`, and why your job did not start
Why a GitLab job is skipped or missing: workflow rules, rules:if, rules:changes, merge request pipelines, and schedules explained for junior and mid-level engineers.
One of the most frustrating GitLab CI questions is not “why did the job fail?” but “why did the job not start at all?” There is no log, no red error, and the expected check is missing from the merge request.
For junior and mid-level engineers this feels like GitLab is broken. Most of the time, workflow: or rules: did exactly what the YAML told them to do.
Who decides whether a job exists
workflow:rules decides whether GitLab creates the pipeline at all. Job-level rules: decide whether a job enters an already-created pipeline. If the pipeline is not created, the job cannot appear. If the pipeline exists but no job rule matches, the job may be skipped or absent depending on the config.
Common causes
1. workflow:rules filtered out the entire pipeline. Example: the config allows only merge request events, but you pushed to a branch.
2. rules:changes did not see the right files. In a monorepo this is useful, but teams often forget shared files: lockfiles, Dockerfiles, shared packages.
3. rules:if checks the wrong variable. CI_COMMIT_BRANCH and CI_MERGE_REQUEST_SOURCE_BRANCH_NAME exist in different pipeline types.
4. Schedules run a different context. Scheduled pipelines often have no MR context, so MR-only rules do not match.
5. when: manual looks like a missing job. The job exists, but waits for a human and may not block the MR.
What to check in the UI
- Pipeline page: was the pipeline created at all?
- Pipeline editor / CI lint: how GitLab evaluates the YAML.
- Pipeline source: push, merge request, schedule, web.
- Variables:
CI_PIPELINE_SOURCE,CI_COMMIT_BRANCH,CI_DEFAULT_BRANCH. - Skipped and manual jobs.
Minimal example
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- when: never
test:
script: npm test
rules:
- changes:
- "packages/app/**"
This pipeline will not be created for a plain push, and test will not appear if only a shared package-lock.json changed.
When the job actually fails
Once rules are correct, the next question is why the job is red. That is where the log matters. Exlogare connects to GitLab CI and posts an RCA directly in the MR, so the author sees not only the status but also the likely cause. Setup is described in GitLab CI ingest.
Related reading
- GitLab Runner: docker, shell, and kubernetes executor failure classes
- GitLab, GitHub, and Bitbucket statuses: a mini glossary for DevOps
Checklist
- Check
CI_PIPELINE_SOURCE. - Separate
workflow:rulesfrom job-levelrules. - Include shared files in
rules:changes. - Test MR pipelines separately from push pipelines.
- Do not confuse skipped and manual jobs.
- For failed jobs, send the log to RCA instead of pasting screenshots into chat.