Diagnostic TeardownDEVOPS

The GitLab Job Did Not Fail. It Was Never Created.

Author
Alex Florian
Published
Updated
Reading time
4 min

A security scan runs when changes are proposed through a merge request, but disappears when someone pushes directly to the same branch. The team checks the runners and opens the scan script. There is no execution log to inspect.

That absence can be the clue. A job has to be created before a runner can execute it. If configuration excludes the scan from this kind of pipeline, neither more runner capacity nor a better scan script will make it appear. [1][2]

This guide uses a deliberately small GitLab example to distinguish job inclusion from execution. It does not assume that every missing scan has the same rule or that the snippets form a complete production pipeline.

Missing, pending, and failed point to different questions

Observed stateThe first question to investigate
No job in the pipelineWas the job included by the effective configuration for this event?
Job exists but is pendingWhat condition, runner, or dependency is preventing execution?
Job ran and failedWhat do its logs, inputs, environment, and commands show?

In the opening situation, the first row matters. The same branch can be involved in several events: a direct push, a merge request, a schedule, or another trigger. Those events can supply different context when GitLab decides which jobs to create. [2]

One rule that produces the symptom

Here is an illustrative job definition. The script path is fictional; the focus is its inclusion rule:

security_scan:
  script: ./ci/security-scan.sh
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

Assuming the relevant pipeline is created and no other effective configuration changes this definition, the rule includes the scan for a merge-request pipeline. A direct-push pipeline does not match. If no rule matches, GitLab does not add the job. Rules are evaluated in order until a match is found. [2]

The branch may contain exactly the same code on both routes. The event is different, which is enough for this definition to produce a different set of jobs.

Event in this isolated illustrationScan created by the rule above?
Merge-request pipelineYes
Direct branch pushNo
Tag pushNo
Scheduled pipelineNo

That table doesn't establish what the policy should be. Perhaps the scan is required only on the merge-request route. Perhaps direct pushes are permitted and also require a scan. The delivery arrangement must answer that before the configuration is changed.

Correct the intended route, not every possible route

Suppose the agreed requirement is to scan merge requests and direct branch pushes. A job-level illustration could use:

rules:
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH'

The branch condition matters because a push pipeline source can also concern a tag. This example deliberately describes branch pushes, not all push events. It is only the job's rules fragment: the wider workflow: rules design must still control which pipelines are created and avoid unintended duplicate push and merge-request pipelines. [1][2]

In a real project, inspect the effective configuration, including included files, extensions, defaults, and relevant variables. A local job block may not contain the whole definition. Also check that the values used in the rule exist when inclusion is evaluated; a value generated later by a running job cannot explain an earlier creation decision. [1][2]

I would change the condition that explains the contrast, then repeat the relevant events. A correct “no” case belongs in that test just as much as a correct “yes.” Making every job run everywhere can create a different policy from the one intended.

The next run answers only the next run

Once the job appears, a pending or failed state may reveal a separate execution problem. That is progress: the investigation has reached a later stage rather than failed to fix the same thing.

There is also a question about earlier releases. Restoring the scan on future runs doesn't supply checks missing from past ones. The appropriate owner should assess the affected paths and decide what the missing evidence requires. That doesn't prove those releases were unsafe; it prevents a new green run from standing in for work never performed.

The absent log helped locate the original mistake. The team was investigating the inside of a job that never existed. Once inclusion and execution are separated, the next repair can address the configuration decision that actually needs to change.