GitLab CI/CD Basics: Simple Pipelines, Advanced Features, and Common Errors
The Working With GitLab CI/CD and Advanced GitLab CI/CD exercises appear across 8 courses including Security Champion, DevSecOps Professional, DevSecOps Expert, and others. These exercises introduce YAML-based pipeline configuration, artifact management, and manual deployment gates. This article covers the most common failure modes learners hit and how to fix them quickly.
Table of Contents
- YAML Syntax and Stage Definitions
- Job Name Must Match Stage Name
- Artifacts: Saving and Sharing Job Output
- allow_failure and Non-Blocking Scan Jobs
- Manual Approval Gates with
when: manual - GitLab CI Startup Timing and 502 Errors
- 2-Hour Machine Timeout
- Common Questions
YAML Syntax and Stage Definitions
Indentation Errors Break the Pipeline
YAML uses whitespace for structure. A single extra or missing space will cause the entire pipeline to fail silently or with a parse error.
Common mistake: Using tabs instead of spaces, or mixing indentation levels.
Fix: Use 2-space indentation consistently. Use the CI Lint tool at CI/CD > Pipelines or CI/CD > Jobs > CI Lint to validate your .gitlab-ci.yml before committing.
Stage Names Are Case-Sensitive
The verification checks for exact stage names. If the exercise asks for stages build, test, integration, staging, prod, these must match exactly. Build or BUILD will fail verification.
stages:
- build
- test
1 - integration
- staging
- prod
Fix: Copy stage names directly from the exercise instructions. Do not rename them.
Don't Rename .gitlab-ci.yml
The pipeline only triggers when the file is named exactly .gitlab-ci.yml. Renaming it to .gitlab-ci1.yml or gitlab-ci.yml will result in the pipeline never running.
Fix: Ensure the file path is /root/django-nv/.gitlab-ci.yml (with the leading dot).
Job Name Must Match Stage Name
Verification Expects Job Name = Stage Name
In the simple pipeline exercise, the task verification script checks that each job's key name matches its stage value. For example:
build:
stage: build
script:
- echo "This is a build step"
If you name the job build-job but set stage: build, the verification will fail.
Fix: The job key name and stage value must be identical: build maps to stage: build, test maps to stage: test, etc.
exit 1 Will Fail the Job
The exercises use exit 1 to intentionally fail a job, demonstrating how CI/CD uses exit codes. A non-zero exit code turns the job red (failed). Exit code 0 is green (passed).
Key concept: CI/CD uses the last command's exit code by default. If your script has multiple commands, only the final one determines pass/fail.
Artifacts: Saving and Sharing Job Output
Artifact Path Must Exist
When you declare an artifact path, the file must be created by the job's script before the job ends. If the path doesn't exist, you'll get:
cannot access 'vulnerabilities.json': No such file or directory
Fix: Ensure the script creates the file before the artifacts section references it:
integration:
stage: integration
script:
- echo "this is an output" > output.txt
artifacts:
paths: [output.txt]
when: always
when: always Is Required for Failed Jobs
By default, artifacts are only saved when a job passes. If your job intentionally fails with exit 1, you need when: always to preserve the output:
artifacts:
paths: [output.txt]
when: always
Without when: always, a failed job's artifacts are discarded.
Artifacts Have a Default Expiration
Without expire_in, artifacts persist indefinitely, consuming runner disk space:
artifacts:
paths: [vulnerabilities.json]
expire_in: 1 week
allow_failure and Non-Blocking Scan Jobs
Security Scans Fail by Design
When you embed a security scanner like Safety or Bandit into the pipeline, it will often find vulnerabilities and return a non-zero exit code. This causes the job to turn red and block the entire pipeline.
Fix: Add allow_failure: true to the scanning job. The job will show an exclamation mark (!) instead of a red X, and the pipeline continues:
sast:
stage: build
script:
- docker run --rm hysnsec/bandit -r /src
allow_failure: true
This is appropriate for DevSecOps Maturity Levels 1-2, where false positives are common and security is being introduced gradually.
Manual Approval Gates with when: manual
Production Deployments Require Human Approval
The when: manual keyword pauses the pipeline at a specific job, requiring a human to click Play in the GitLab UI before proceeding:
deploy:
stage: deploy
script:
- echo "This is a deploy step."
when: manual
Common mistake: Forgetting when: manual causes the pipeline to auto-deploy to production, which is a security risk.
GitLab CI Startup Timing and 502 Errors
GitLab Takes 3-5 Minutes to Start
When you first click Start the Exercise, GitLab CE needs time to initialize. During startup:
- 502 Bad Gateway means GitLab is still booting. Wait 2-3 minutes and refresh.
- 404 Not Found after waiting means the machine has been recycled. Refresh the exercise page and click Start the Exercise again.
Fix: If you see 502, be patient. If you see 404 after 5+ minutes, the 2-hour timeout has hit — restart the exercise.
GitLab Login Credentials
- Username:
root - Password:
pdso-training - URL pattern:
https://gitlab-ce-<machine-id>.lab.practical-devsecops.training
2-Hour Machine Timeout
All lab machines have a 2-hour active session limit. Every machine — GitLab CE, GitLab Runner, and DevSecOps Box — resets independently. When the timeout hits:
- GitLab returns 404
- All committed code is lost
- All pipeline configurations are wiped
Fix: Refresh the exercise page and click Start the Exercise again. There is no way to preserve progress. The DevSecOps Box is stateless and resets on any page refresh or tab close.
Common Questions
| Question | Answer |
|---|---|
| My pipeline isn't running after I commit. | Check that the file is named exactly .gitlab-ci.yml (with the dot). Use CI Lint to validate syntax. |
| I see "Invalid yaml" in the pipeline. | Check indentation. YAML requires consistent 2-space indentation. No tabs allowed. |
| My job shows red even though the commands ran. | The last command returned a non-zero exit code. Check for exit 1 or a failing command. Add allow_failure: true if intended. |
| Artifacts aren't appearing after the job runs. | The file path in artifacts: paths: must match exactly what the script creates. If the job fails, add when: always. |
How do I validate my .gitlab-ci.yml before committing? |
Use CI Lint at CI/CD > Pipelines or CI/CD > Jobs > CI Lint in the GitLab UI. |
| The verification says "One or more stage/job is missing." | Ensure every job's key name matches its stage value exactly (e.g., build: with stage: build). |
Wrap-Up
GitLab CI/CD pipelines are the backbone of automated security testing in these exercises. Remember: YAML indentation matters, job names must match stage names, use artifacts with when: always to save output from failing jobs, add allow_failure: true for security scans that find vulnerabilities, and use when: manual for production deployment gates. Every machine resets after 2 hours — there is no way to save progress.
Reach out to support with your lab ID if you encounter errors not covered in this guide.