| title | GitLab Invalid CI Config β YAML / .gitlab-ci.yml Error | |||||
|---|---|---|---|---|---|---|
| slug | gitlab-invalid-ci-config-yaml | |||||
| technologies |
|
|||||
| severity | medium | |||||
| tags |
|
|||||
| related |
|
|||||
| last_reviewed | 2026-06-27 |
Found errors in your .gitlab-ci.yml:
jobs:build config contains unknown keys: scripts
jobs:test:rules config should be an array of hashes
This GitLab CI configuration is invalid: jobs config should contain at least one visible job
GitLab validates .gitlab-ci.yml before creating any pipeline. If the file is
not valid YAML, or is valid YAML but violates the CI schema (unknown keywords,
wrong value types, undefined extends/needs targets), GitLab refuses to create
the pipeline and shows a red banner on the Pipelines page or in the Pipeline
Editor. No job runs β the whole pipeline is rejected at lint time. This is
distinct from a job that runs and fails; here nothing runs at all.
- gitlab (pipeline configuration parser/linter)
medium β no pipeline is created, so merges and deploys are blocked, but the fix is a config edit and there is no runtime breakage.
- YAML syntax errors: bad indentation, tabs instead of spaces, an unquoted value
containing
:, or a missing/misaligned list item. - A typo'd keyword (
scripts:instead ofscript:,stage:vsstages:). - Wrong value type β e.g.
rules:given a mapping instead of a list of mappings, ortags:given a string instead of a list. extends:orneeds:referencing a job/template that does not exist.- An
include:target that is missing, on the wrong ref, or itself invalid.
GitLab parses the YAML, merges all include: and extends: chains, then
validates the merged document against the CI schema. Two failure classes exist:
parse errors (the YAML itself is malformed) and schema errors (valid YAML,
illegal CI structure). The error message names the path that failed
(jobs:build config contains unknown keys: scripts), which points you to the
exact job and key. Because validation happens before scheduling, the failure is
fully deterministic and reproducible with the CI Lint tool.
# 1) Check raw YAML validity first (parse errors)
yamllint .gitlab-ci.yml || python3 -c "import yaml,sys; yaml.safe_load(open('.gitlab-ci.yml'))"
# 2) Reveal hidden tabs/trailing whitespace that break YAML
grep -nP '\t' .gitlab-ci.yml # tabs are illegal indentation in YAML
cat -A .gitlab-ci.yml | head -n 40 # ^I marks tabs, $ marks line ends
# 3) Inspect included files and extends targets referenced by the config
grep -nE 'include:|extends:|needs:|template:' .gitlab-ci.yml
# 4) Validate the merged config via the CI Lint API (read-only)
curl -s --header "PRIVATE-TOKEN: $GL_TOKEN" \
"https://gitlab.com/api/v4/projects/<id>/ci/lint?include_merged_yaml=true"# yamllint flags the structural problem:
.gitlab-ci.yml:14:1 error found character '\t' that cannot start any token (syntax)
# CI Lint API returns:
{"valid":false,"errors":["jobs:build config contains unknown keys: scripts"]}
# Healthy:
{"valid":true,"errors":[],"warnings":[]}
-
Fix YAML structure first: replace tabs with spaces, align list items, quote any value containing
:. -
Correct the keyword the error names. For the example,
scripts->script:build: stage: build script: # not "scripts" - make build
-
Ensure
rules:is a list of mappings:test: rules: - if: '$CI_COMMIT_BRANCH == "main"'
-
Verify every
extends:/needs:target exists and thatinclude:files are on a reachable ref.
# Re-lint after editing; expect "valid": true
curl -s --header "PRIVATE-TOKEN: $GL_TOKEN" \
"https://gitlab.com/api/v4/projects/<id>/ci/lint" \
--data-urlencode "[email protected]" | grep -o '"valid":[a-z]*'- Run the CI Lint API (or the Pipeline Editor's live validation) in a pre-merge
check on the
.gitlab-ci.ymlitself. - Use the GitLab Pipeline Editor, which validates as you type and resolves
include/extends. - Add
yamllintto a fast pre-commit hook to catch tabs/indentation early.
gitlab Β· ci Β· yaml Β· config Β· production