This GitLab CI/CD error occurs when one or more jobs in your pipeline fail. The failure can be caused by test failures, script errors, configuration issues, or external dependencies. To fix it, examine the job logs, identify the root cause, and resolve the underlying issue.
When you see "Pipeline failed: Job 'test' failed" (or any similar job name), GitLab is telling you that one of the jobs defined in your CI/CD pipeline did not complete successfully. A job fails when its script returns a non-zero exit code. GitLab CI/CD pipelines consist of stages, and each stage can have multiple jobs. When a job fails, it typically prevents downstream jobs and stages from running (unless configured otherwise with `allow_failure`). The pipeline as a whole is marked as failed. This is GitLab's way of protecting your codebase from broken code being deployed or merged. The failed job indicates that something went wrong - it could be failing tests, a build error, a linting violation, a deployment issue, or even a misconfigured CI script. Understanding why the job failed requires examining the job logs, which show the exact command that failed and any error output. The job name in the error message (like 'test', 'build', 'lint', or 'deploy') gives you a hint about what type of failure occurred.
First, identify what caused the job to fail by examining the logs:
1. Navigate to your project in GitLab
2. Click on Build > Pipelines in the sidebar
3. Find the failed pipeline and click on it
4. Click on the failed job (marked with red X)
5. Review the job log output
# Example job log showing a test failure:
$ npm test
FAIL src/utils.test.js
✕ should return correct sum (5 ms)
● should return correct sum
expect(received).toBe(expected)
Expected: 5
Received: 4
Test Suites: 1 failed, 1 total
ERROR: Job failed: exit code 1The key information is usually near the end of the log, right before "Job failed". Look for error messages, stack traces, or assertion failures.
Before making changes, reproduce the issue on your machine:
# Pull the latest code
git fetch origin
git checkout your-branch
# Run the same command that failed in CI
# For test failures:
npm test
# or
pytest
# or
go test ./...
# or
mvn test
# For build failures:
npm run build
# or
make build
# For lint failures:
npm run lint
# or
eslint .Tip: If the failure only happens in CI, check for environment differences:
- Different Node/Python/Go version
- Missing environment variables
- Cached dependencies vs fresh install
- Different OS (GitLab runner vs local machine)
To match CI environment more closely:
# Clear caches and reinstall
rm -rf node_modules package-lock.json
npm install
npm testIf the job failed due to failing tests, fix the tests or the code:
Common test failure scenarios:
1. Assertion failure - Update the test or fix the code:
// Fix the actual code
function add(a, b) {
return a + b; // was: return a - b;
}2. Snapshot mismatch - Update snapshots if changes are intentional:
npm test -- --updateSnapshot
# or
jest --updateSnapshot3. Async test timeout - Increase timeout or fix async handling:
test('async operation', async () => {
jest.setTimeout(10000); // Increase timeout
const result = await slowOperation();
expect(result).toBeDefined();
}, 10000);4. Environment-dependent test - Mock external dependencies:
// Mock API calls that may fail in CI
jest.mock('./api', () => ({
fetchData: jest.fn().mockResolvedValue({ data: 'test' })
}));After fixing, push your changes:
git add .
git commit -m "fix: resolve failing tests"
git push origin your-branchFor build failures, address the compilation or bundling issues:
TypeScript/JavaScript build errors:
# Check for TypeScript errors
npx tsc --noEmit
# Common fixes:
# - Add missing type definitions
# - Fix type mismatches
# - Install missing @types packages
npm install --save-dev @types/nodeImport/export issues:
// Wrong - named vs default export mismatch
import MyComponent from './MyComponent'; // expects default export
export const MyComponent = () => {}; // but this is named export
// Fix:
export default MyComponent;
// or
import { MyComponent } from './MyComponent';Missing dependencies:
# Install missing packages
npm install missing-package
# For monorepos, ensure you're in the right directory
cd packages/my-app
npm installDocker build failures:
# Ensure base image exists
FROM node:18-alpine # Use specific version
# Copy package files before code for better caching
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run buildCheck your .gitlab-ci.yml for configuration issues:
Validate your CI configuration:
1. Go to Build > Pipeline editor in GitLab
2. Paste your .gitlab-ci.yml content
3. Click Validate to check for syntax errors
Common configuration mistakes:
1. Using tabs instead of spaces:
# Wrong - YAML requires spaces, not tabs
test:
script: npm test # Tab character!
# Correct:
test:
script: npm test2. Missing script keyword:
# Wrong:
test:
- npm test
# Correct:
test:
script:
- npm test3. Invalid before_script usage:
# Correct structure:
test:
before_script:
- npm ci
script:
- npm test4. Stage not defined:
# Must define stages used by jobs
stages:
- test
- build
- deploy
test-job:
stage: test # Must be in stages list
script:
- npm testFix problems related to environment variables and dependencies:
Missing environment variables:
# Define variables in .gitlab-ci.yml
variables:
NODE_ENV: "test"
DATABASE_URL: $CI_DATABASE_URL # Use CI/CD variables
test:
script:
- npm testSet sensitive variables in GitLab:
1. Go to Settings > CI/CD > Variables
2. Add your variable (e.g., API_KEY)
3. Mark as "Masked" for sensitive values
Dependency installation failures:
# Use npm ci for clean installs in CI
install:
script:
- npm ci # Not 'npm install'
# Or with caching:
test:
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
script:
- npm ci
- npm testDocker image issues:
# Specify exact image version
test:
image: node:18.17.0-alpine
script:
- npm ci
- npm test
# For custom registries, authenticate first
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRYIf the failure appears to be transient (network timeout, flaky test), retry the job:
Manual retry:
1. Navigate to the failed job
2. Click Retry button in the top-right corner
Configure automatic retry in .gitlab-ci.yml:
test:
script:
- npm test
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure
- script_failure # For flaky tests
# Different retry for different failure types:
deploy:
script:
- ./deploy.sh
retry:
max: 1
when:
- runner_system_failure
- stuck_or_timeout_failure
# Don't retry script failures for deploymentRetry entire pipeline:
- Push an empty commit to trigger a new pipeline:
git commit --allow-empty -m "ci: retry pipeline"
git push origin your-branchOr use GitLab quick actions in MR comments:
/rebaseIf your job is timing out, extend the timeout or optimize the job:
Increase job timeout:
test:
script:
- npm test
timeout: 30 minutes # Default is usually 1 hour
# For very long jobs:
e2e_tests:
script:
- npm run test:e2e
timeout: 2 hoursOptimize job execution:
# Run tests in parallel
test:
parallel: 4
script:
- npm test -- --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
# Use caching effectively
test:
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- node_modules/
- .npm/
script:
- npm ci --cache .npm
- npm test
# Split into multiple jobs
test_unit:
stage: test
script:
- npm run test:unit
test_integration:
stage: test
script:
- npm run test:integrationCheck runner resources:
- Request larger runner if available
- Check if shared runners are overloaded
- Consider using your own runners for resource-intensive jobs
For non-critical jobs, configure them to not block the pipeline:
# Job can fail without failing the pipeline
optional_lint:
script:
- npm run lint:experimental
allow_failure: true
# Allow failure only for specific exit codes
test_new_feature:
script:
- npm test -- --experimental
allow_failure:
exit_codes:
- 1
- 137 # OOM killed
# Allow failure only on specific branches
staging_deploy:
script:
- ./deploy.sh staging
allow_failure: true
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCHUse this sparingly - only for truly optional jobs like:
- Experimental feature tests
- Non-blocking code quality checks
- Optional security scans
- Performance benchmarks
Warning: Don't use allow_failure to hide real problems!
### Understanding Job Exit Codes
Common exit codes and their meanings:
| Exit Code | Meaning | Common Cause |
|-----------|---------|--------------|
| 1 | General error | Test failure, script error |
| 2 | Misuse of command | Invalid arguments |
| 126 | Permission denied | Script not executable |
| 127 | Command not found | Missing binary/tool |
| 128 | Invalid exit argument | Script returned invalid code |
| 137 | SIGKILL (128+9) | Out of memory, killed by system |
| 139 | SIGSEGV (128+11) | Segmentation fault |
| 143 | SIGTERM (128+15) | Job timeout, terminated |
### Debugging with Artifacts
Preserve logs and artifacts from failed jobs:
test:
script:
- npm test
artifacts:
when: on_failure # Only upload on failure
paths:
- test-results/
- coverage/
- logs/
expire_in: 1 week### Using rules vs only/except
Modern GitLab CI uses rules instead of only/except:
# Modern approach with rules:
test:
script:
- npm test
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Avoid deprecated only/except syntax:
# only:
# - merge_requests
# - main### Needs and Dependencies
Control job execution order with needs:
stages:
- build
- test
- deploy
build:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
test:
stage: test
needs: ["build"] # Wait only for build, not all of previous stage
script:
- npm test
deploy:
stage: deploy
needs: ["build", "test"]
script:
- ./deploy.sh### Using Services for Integration Tests
For tests requiring databases or other services:
test:
image: node:18
services:
- postgres:15
- redis:7
variables:
POSTGRES_DB: test_db
POSTGRES_USER: test
POSTGRES_PASSWORD: test
DATABASE_URL: "postgresql://test:test@postgres:5432/test_db"
REDIS_URL: "redis://redis:6379"
script:
- npm ci
- npm run db:migrate
- npm test### Interruptible Jobs
Stop redundant pipelines when new commits are pushed:
workflow:
auto_cancel:
on_new_commit: interruptible
test:
interruptible: true
script:
- npm test
deploy:
interruptible: false # Never cancel deployments
script:
- ./deploy.sh### Troubleshooting Runner Issues
If jobs fail due to runner problems:
# Request specific runner tags
test:
tags:
- docker
- linux
script:
- npm test
# Check runner configuration
variables:
# For Docker-in-Docker
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"Contact your GitLab administrator if shared runners consistently fail.
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git