Skip to content
CloudOps
All prompts
AI for GitLab CI/CD Difficulty: Intermediate ClaudeChatGPT

GitLab Merge Request Pipeline Debug Prompt

Diagnose MR pipeline issues — pipeline not running, duplicate detached + branch pipelines, merge train failures, missing MR variables, ref:`merge` vs `head` SHA.

Target user
DevOps engineers debugging GitLab merge request pipelines
Difficulty
Intermediate
Tools
Claude, ChatGPT

The prompt

You are a senior DevOps engineer with deep experience operating GitLab Merge Request pipelines, merged-results pipelines, and merge trains in production. You know the pipeline types — branch, detached MR, merged-results, merge-train — and how they differ from a plain push pipeline.

I will provide:
- The MR ID and target branch
- The symptom (no pipeline on MR, duplicate pipelines, "couldn't be merged" with a green pipeline, merge train failing, MR variables empty)
- Project settings for MR pipelines:
  - "Pipelines for merge requests" enabled?
  - "Merged results pipelines" enabled? (Premium+)
  - "Merge trains" enabled? (Premium+)
- The `.gitlab-ci.yml` `workflow:` and the job's `rules:`
- GitLab tier (Free/Premium/Ultimate)
- Output of the pipeline UI showing which pipeline ran (or didn't)

Your job:

1. **Identify the pipeline type that's expected vs. that actually ran**:
   - **Branch pipeline**: runs against `$CI_COMMIT_SHA`. Default for pushes. `$CI_PIPELINE_SOURCE == "push"`.
   - **Detached MR pipeline**: runs against the MR's source branch HEAD. `$CI_PIPELINE_SOURCE == "merge_request_event"`. UI labels it "detached" because it's not strictly tied to a commit history thread.
   - **Merged results pipeline** (Premium+): runs against a *temporary* merge commit of MR into target. Catches "passes individually, breaks when merged" issues.
   - **Merge train pipeline** (Premium+): like merged results but serialized — Train members tested in order.
2. **Decode the "no pipeline runs on MR open"** failure modes:
   - `workflow:rules:` rejects the MR pipeline (most common)
   - Job-level `rules:` exclude every job → empty pipeline → GitLab may report "no pipeline"
   - Project setting "Pipelines for merge requests" disabled
   - Source branch protected and runner not protected
   - GitLab user permissions: contributor lacks "Run pipeline" perm on protected branch
3. **Decode "two pipelines on every MR push"**:
   - Standard double-pipeline: branch pipeline + detached MR pipeline = 2 pipelines, both running tests
   - Fix with this workflow rule:
     ```yaml
     workflow:
       rules:
         - if: $CI_PIPELINE_SOURCE == "merge_request_event"
         - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
           when: never
         - if: $CI_COMMIT_BRANCH
     ```
4. **MR-specific predefined variables** to verify usage:
   - `$CI_MERGE_REQUEST_IID` — short ID (e.g., 42), local to project
   - `$CI_MERGE_REQUEST_ID` — global ID
   - `$CI_MERGE_REQUEST_TARGET_BRANCH_NAME` — destination
   - `$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` — source
   - `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` — important for forks
   - `$CI_MERGE_REQUEST_TITLE`, `$CI_MERGE_REQUEST_LABELS`
   - `$CI_COMMIT_BRANCH` is EMPTY on detached MR pipelines (a common trap)
5. **For "couldn't be merged" with green pipeline**:
   - Merged-results pipeline differs from MR pipeline — required pipeline status may be the merged-results one
   - Approvals or status checks blocking
   - Source branch out of date with target — needs rebase
   - "Pipelines must succeed before merge" enabled and most-recent pipeline is queued/running
6. **For merge train failures**:
   - Trains require linear, fast-forward-able state per member
   - Train item ahead failed → all behind are re-tested with new merge
   - Long jobs make trains slow; consider `interruptible: true` (carefully — not for deploys)
7. **For fork MRs (external contributors)**:
   - Forks DON'T have access to the parent project's CI/CD variables (security!)
   - Protected variables especially won't be available
   - Some jobs (deploy, integration tests) need fork-pipeline allowed manually
8. **Job-level checks**:
   - `rules:` matching `$CI_PIPELINE_SOURCE == "merge_request_event"` will skip on branch pipelines
   - `rules:` matching `$CI_COMMIT_BRANCH == "main"` will skip on MR pipelines (because `$CI_COMMIT_BRANCH` is empty)
9. Mark anything DESTRUCTIVE: editing workflow rules during an active merge train, disabling merged-results mid-batch.

---

MR ID + target branch: [DESCRIBE]
GitLab tier: [Free / Premium / Ultimate]
MR pipeline settings:
  - Pipelines for MRs: [enabled / disabled]
  - Merged results pipelines: [enabled / disabled]
  - Merge trains: [enabled / disabled]
Symptom: [DESCRIBE]
`workflow:rules:` (if present):
```yaml
[PASTE]
```
Relevant job's `rules:`:
```yaml
[PASTE]
```
Pipeline outcome (UI text):
[DESCRIBE]

Why this prompt works

MR pipelines have multiple types, settings, and gotchas. “Pipeline didn’t run on my MR” can be: workflow rules, rules excluding every job, project setting off, fork without permissions, or protected-branch quirk. This prompt forces a type-first diagnosis.

How to use it

  1. State the pipeline type GitLab actually ran (or didn’t). It’s labeled in the UI as “branch,” “detached,” or “merged result.”
  2. Include project settings: which MR pipeline features are enabled. Toggle settings interact.
  3. For fork MRs, mention “this is from a fork” — diagnostic changes (no secrets, manual run sometimes required).
  4. Capture workflow:rules: — most MR pipeline issues live here.

Pipeline-type cheatsheet

Type$CI_PIPELINE_SOURCE$CI_COMMIT_BRANCHUse case
BranchpushSetNormal pushes
Detached MRmerge_request_eventEMPTYMR-specific tests
Merged resultsmerge_request_eventEMPTYTest “post-merge” state (Premium+)
Merge trainmerge_request_eventEMPTYSerialized merge testing (Premium+)
SchedulescheduleSetCron-style
Manual (Run pipeline)webSetOne-off
API triggerapi, triggerSet / EmptyPipeline orchestration

Useful API queries

# Get pipelines for an MR
curl --header "PRIVATE-TOKEN: <t>" \
  "https://gitlab.example.com/api/v4/projects/<id>/merge_requests/<iid>/pipelines" | jq

# Detailed pipeline including source
curl --header "PRIVATE-TOKEN: <t>" \
  "https://gitlab.example.com/api/v4/projects/<id>/pipelines/<pid>" | jq

# Variables available at the pipeline
curl --header "PRIVATE-TOKEN: <t>" \
  "https://gitlab.example.com/api/v4/projects/<id>/pipelines/<pid>/variables" | jq

# Merge status (UI checks)
curl --header "PRIVATE-TOKEN: <t>" \
  "https://gitlab.example.com/api/v4/projects/<id>/merge_requests/<iid>?include_diverged_commits_count=true&include_rebase_in_progress=true" | jq

Workflow patterns

Standard: avoid duplicate pipelines

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG

Result: MR push runs only the MR pipeline; default branch push and tags run their pipelines; other branches without MRs skip.

Test gates differ on MR vs default

test-unit:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

test-integration:
  # Heavy — only on MRs targeting default branch, or on default branch
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy-staging:
  # Only on default branch after merge
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Skip CI on docs-only

workflow:
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /\[skip ci\]/
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH

Common findings this catches

  • “No pipeline on MR” with workflow rules that only match $CI_COMMIT_BRANCH$CI_COMMIT_BRANCH is empty on MR pipelines. Add merge_request_event source rule.
  • Two pipelines per MR push → standard duplicate; apply the workflow rule above.
  • Merged-results pipeline expected, only detached running → “Merged results pipelines” toggle off in project settings (Premium+).
  • Merge button disabled with green pipeline → required pipeline is the merged-results one, but only detached ran. Or: approvals/status checks blocking.
  • Fork MR’s deploy job has empty $AWS_KEY → protected variable, fork has no access. Don’t deploy from fork pipelines; require maintainer to push to a branch.
  • Merge train member fails over and over → fix at the front of the train; behind-the-front members re-test with each front change.
  • $CI_MERGE_REQUEST_IID empty in detached pipeline → check: is this actually an MR pipeline? Or did someone trigger via API as a branch pipeline?

Merge train tips

  • Use interruptible: true on tests, false on deploys
  • Long pipelines → fewer trains/hour; consider whether train is worth it
  • Restart a single failing member sometimes recovers (transient infrastructure issue) without invalidating others ahead

When to escalate

  • Merge train backed up severely → coordinate; possibly disable trains temporarily and re-test.
  • Settings discrepancy between group default and project override → align with platform team’s policy.
  • External fork MRs from a security-sensitive contributor — likely needs manual review and an internal-branch flow, not auto-pipelines.

Related prompts

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.