GitLab CI Error Guide: 'parallel should be an integer' — Fix Parallel Config
Fix 'parallel config should be an integer between 1 and 200' in GitLab CI: set a valid count, quote matrix values, and split parallel from parallel:matrix.
- #gitlab
- #ci-cd
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
GitLab rejects the pipeline configuration when a job’s parallel: keyword has a value outside the allowed range or of the wrong type. The parser fails before any job runs:
Found errors in your .gitlab-ci.yml:
jobs:test:parallel config should be an integer between 1 and 200
The parallel:matrix: variant reports a related shape error when the matrix isn’t a proper list of variable maps:
jobs:test:parallel:matrix config should be an array of hashes
Either way the config is invalid and no pipeline is created until the value is corrected.
Symptoms
- The pipeline fails at parse time citing
paralleland the 1–200 range. - A
parallel:value came from a variable that expanded to a non-integer or empty string. - Someone set
parallel: 0or a very large number expecting “as many as possible.” - A
parallel:matrix:block is written as a map instead of a list, or matrix values aren’t quoted strings. - CI Lint flags the job while the surrounding YAML looks correct.
Common Root Causes
- Out-of-range value —
parallel: 0, a negative number, or a value above 200. - Non-integer / variable value —
parallel: "$SHARDS"where the variable is empty or non-numeric (parallel:does not interpolate variables the wayscript:does). - Quoted where a number is required — some contexts accept
parallel: "5", but a malformed/empty quoted value fails. - Confusing
parallelwithparallel:matrix— using a bare integer when you meant a matrix, or vice versa. - Malformed matrix shape —
parallel:matrix:written as a single mapping rather than a list (-) of variable maps. - Unquoted matrix values that YAML mistypes — a version like
3.10parsed as a float3.1, oron/noparsed as booleans.
Diagnostic Workflow
Validate the config and confirm the exact keyword shape with CI Lint:
lint:
image: curlimages/curl:latest
script:
- |
curl --silent --header "PRIVATE-TOKEN: $LINT_TOKEN" \
"https://$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/ci/lint" \
--data-urlencode "content=$(cat .gitlab-ci.yml)"
For a simple sharded job, use a literal integer in range — not a variable:
# Valid: literal integer, 1..200 — creates N parallel job instances
test:
parallel: 5
script:
- ./run-shard.sh "$CI_NODE_INDEX" "$CI_NODE_TOTAL"
For a matrix, write a LIST of variable maps and quote values so YAML doesn’t retype them:
# Valid parallel:matrix — a sequence (-) of hashes, all values quoted
test:
parallel:
matrix:
- PYTHON: ["3.10", "3.11", "3.12"] # quoted so 3.10 stays a string
DB: ["postgres", "mysql"]
script:
- ./test.sh
Example Root Cause Analysis
A team wanted the shard count configurable per environment, so they wired it through a variable:
variables:
SHARDS: "" # default left empty, set per-schedule
test:
parallel: "$SHARDS" # <-- parallel does not interpolate this
script:
- ./run-shard.sh
The pipeline failed with jobs:test:parallel config should be an integer between 1 and 200. The parallel: keyword is resolved at config-parse time and does not expand CI variables the way script lines do — "$SHARDS" was treated as a literal, non-integer string (and was empty besides). The fix was to use a literal integer, and where per-context variation was genuinely needed, to select among predefined jobs with rules: rather than trying to interpolate the count:
test:
parallel: 8 # literal integer in range
script:
- ./run-shard.sh "$CI_NODE_INDEX" "$CI_NODE_TOTAL"
For the rare case that truly needed a variable shard count, they generated the job via a dynamic child pipeline, where the count is computed and written into the generated YAML as a literal before it is triggered.
Prevention Best Practices
- Use a literal integer between 1 and 200 for
parallel:; don’t feed it a CI variable, which it won’t interpolate at parse time. - For version/OS matrices, use
parallel:matrix:as a sequence of variable maps, not a single mapping. - Quote matrix values (
"3.10","on","no") so YAML doesn’t retype them as floats or booleans. - Run CI Lint in a pre-merge job to catch range/shape errors before the default branch.
- When you genuinely need a computed count, generate it into a dynamic child pipeline as a literal, rather than interpolating
parallel:. - Keep
parallel(simple sharding) andparallel:matrix(dimension expansion) conceptually separate and pick the right one deliberately.
Quick Command Reference
# Validate the config locally
glab ci lint .gitlab-ci.yml
# CI Lint via API
curl --header "PRIVATE-TOKEN: $TOKEN" \
"https://gitlab.example.com/api/v4/projects/$PROJECT_ID/ci/lint" \
--data-urlencode "content=$(cat .gitlab-ci.yml)"
# Confirm a matrix value stays a string in YAML (float trap)
python -c "import yaml,sys; print(yaml.safe_load('v: 3.10'))" # -> {'v': 3.1} if unquoted!
python -c "import yaml,sys; print(yaml.safe_load('v: \"3.10\"'))" # -> {'v': '3.10'}
Conclusion
parallel config should be an integer between 1 and 200 means the parallel: value is out of range, the wrong type, or an un-interpolated variable — GitLab resolves this keyword at parse time and won’t expand CI variables into it. Use a literal integer in range, express version/OS fan-out with a properly-shaped parallel:matrix: list of quoted variable maps, and validate with CI Lint. When you truly need a computed shard count, generate it into a dynamic child pipeline instead of interpolating parallel:.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.