# GitLab

> Avoid common GitLab CI/CD mistakes — rules gotchas, silent failures, and YAML merge traps.

- Skill: `modbender/gitlab` (Agent Skill)
- Install (CLI): `npx skillmds@latest add modbender/gitlab`
- Raw SKILL.md: https://api.skillmd.com/api/skills/modbender/gitlab/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: modbender (https://skillmd.com/u/modbender)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/modbender/gitlab

---


## Rules Gotchas
- `rules:` and `only:/except:` can't mix — use one or the other per job
- First matching rule wins — put specific rules before general ones
- Missing `when:` defaults to `on_success` — `rules: - if: $CI_COMMIT_TAG` runs on tag
- Empty rules array `rules: []` means never run — different from no rules at all
- Add `- when: never` at end to prevent fallthrough — otherwise unmatched conditions may run

## Silent Failures
- Protected variables missing on non-protected branches — job runs but variable is empty
- Runner tag mismatch — job stays pending forever with no error
- `docker:dind` on non-privileged runner — fails with cryptic Docker errors
- Masked variable format invalid — variable exposed in logs anyway

## YAML Merge Traps
- `extends:` doesn't deep merge arrays — scripts, variables arrays get replaced, not appended
- Use `!reference [.job, script]` to reuse — `script: [!reference [.base, script], "my command"]`
- `include:` files can override each other — last one wins for same keys
- Anchors `&`/`*` don't work across files — use `extends:` for cross-file reuse

## Artifacts vs Cache
- Cache not guaranteed between runs — treat as optimization, not requirement
- Artifacts auto-download by stage — add `dependencies: []` to skip if not needed
- `needs:` downloads artifacts by default — `needs: [{job: x, artifacts: false}]` to skip

## Docker-in-Docker
- Shared runners usually don't support privileged — need self-hosted or special config
- `DOCKER_HOST: tcp://docker:2375` required — job uses wrong Docker otherwise
- `DOCKER_TLS_CERTDIR: ""` or configure TLS properly — half-configured TLS breaks builds

## Pipeline Triggers
- `CI_PIPELINE_SOURCE` differs by trigger — `push`, `merge_request_event`, `schedule`, `api`, `trigger`
- MR pipelines need `rules: - if: $CI_MERGE_REQUEST_IID` — not just branch rules
- Detached vs merged result pipelines — detached tests source, merged tests result of merge

