GitLab CI Error Guide: 'Included file does not exist' Broken include: Resolution
Fix GitLab's 'Local file does not exist' and 'Project reference does not have a file': repair include:local, include:project, include:remote, and component refs.
- #gitlab-cicd
- #troubleshooting
- #errors
- #yaml
Exact Error Message
When an include: in .gitlab-ci.yml cannot be resolved, GitLab rejects the whole config before any job runs. The exact wording depends on which include type failed:
Local file `templates/deploy.yml` does not exist!
Project `group/ci-templates` reference `main` does not have a file named `/jobs/build.yml`.
Included file `https://example.com/ci/remote.yml` does not have valid YAML syntax!
Included file `templates/deploy.yml` is empty or does not exist!
You see these in the Pipeline Editor’s Validate tab, on push, from the CI Lint tool at /-/ci/lint, or via glab ci lint.
What the Error Means
GitLab assembles your pipeline config by merging every include: into one document before it validates the schema. Resolution happens first: GitLab fetches each included file by its path and ref, parses it as YAML, then stitches it into the parent. If any include cannot be fetched (wrong path, missing ref, 404, auth failure) or the fetched file is not valid YAML, the merge fails and no pipeline is created.
This is distinct from the general Invalid CI config error — there the file itself broke a schema rule. Here the file you wrote is fine, but a file it pulls in cannot be located or read. The fix is always about the include reference (path, project, ref, URL), not the job definitions.
Common Causes
include:localpath is wrong. The path must be relative to the repository root, with a leading slash (/templates/deploy.yml), not relative to.gitlab-ci.ymland not a filesystem path.include:projectfile/ref is wrong. Thefile:must be repo-root absolute in the target project, and theref:(branch, tag, or SHA) must actually exist there.include:projectpermissions. The pipeline’s identity cannot read a private target project, so the file appears “missing.”include:remoteURL 404s or needs auth. A remote include must be a publicly reachable, fully qualifiedhttps://URL returning raw YAML — auth-gated or HTML pages fail.include:componentversion is wrong. The@version after the component path must match a released tag,~latest, or a commit the catalog exposes.- The file lives on a different branch.
include:localalways reads from the same ref as the running pipeline; the template you added onmainis invisible to a feature-branch pipeline. - Circular includes. Two files include each other, or a file includes itself, and GitLab refuses to resolve the loop.
- Empty or whitespace-only file. A file that exists but has no YAML content triggers
is empty or does not exist.
How to Reproduce the Error
Reference a local file that does not exist on the current ref:
# .gitlab-ci.yml on a feature branch
include:
- local: '/templates/deploy.yml' # only added on main, not this branch
build:
stage: build
script: ["make build"]
Or point a project include at a ref that has no such file:
include:
- project: 'group/ci-templates'
ref: 'main'
file: '/jobs/build.yml' # build.yml is under /ci/, not /jobs/
Both produce a hard validation failure on push:
Local file `/templates/deploy.yml` does not exist!
Diagnostic Commands
Run the CI Lint tool with includes expanded so resolution actually runs:
glab ci lint --include
✗ Invalid configuration
Project `group/ci-templates` reference `main` does not have a file named `/jobs/build.yml`.
Lint via the API to script it in CI:
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.com/api/v4/projects/$PROJECT_ID/ci/lint" \
--data-urlencode "content=$(cat .gitlab-ci.yml)" \
--data "include_jobs=true" | jq '.errors'
Confirm the file and ref exist in the target project:
# Does the path exist on that ref?
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.com/api/v4/projects/group%2Fci-templates/repository/files/jobs%2Fbuild.yml?ref=main"
# Same-repo local include: is the file on THIS branch?
git ls-files templates/deploy.yml
git show "$CI_COMMIT_REF_NAME:templates/deploy.yml" | head
In the UI, open Project > Build > Pipeline Editor, then the Full configuration (View merged YAML) tab — it shows exactly what each include resolved to, or where resolution stopped.
Step-by-Step Resolution
For include:local — make the path repo-root absolute and confirm it is on the running ref:
include:
- local: '/templates/deploy.yml' # leading slash, from repo root
If the file only exists on main, either merge it into your branch or switch to a project: include pinned to main.
For include:project — verify the project path, the file: (leading slash, target-repo-root relative), and a real ref::
include:
- project: 'group/ci-templates'
ref: 'v2.3.0' # a tag that exists
file: '/ci/build.yml' # the real path in that repo
Grant the pipeline read access to private target projects (CI/CD job token allowlist, or make the templates project visible to the group).
For include:remote — use a fully qualified raw URL that returns YAML with no auth:
include:
- remote: 'https://gitlab.com/group/ci-templates/-/raw/main/ci/build.yml'
A 404 means the URL is wrong; an HTML response means you linked the file’s web page, not its raw content.
For include:component — pin a version the catalog actually publishes:
include:
- component: 'gitlab.com/my-org/templates/build@1.2.0'
For circular includes — break the loop so includes form a tree, not a cycle. Pull shared jobs into a third leaf file that both parents include, rather than having them include each other.
Re-run glab ci lint --include until it returns Configuration is valid, then view the merged YAML to confirm the included jobs appear.
Prevention and Best Practices
- Pin every
include:to a tag or SHA, never a moving branch, so a template moved or deleted upstream fails predictably instead of silently shifting. - Always use repo-root-absolute paths with a leading slash for
local:andfile:; relative-looking paths are the single most common cause. - Lint with
--include(orinclude_jobs=trueon the API) in a pre-commit hook and in CI, so resolution errors are caught before they reach a protected branch. - Keep
workflow:and shared jobs in a dedicated templates project with controlled visibility, and document the exactrefconsumers should pin. - Use the Pipeline Editor’s merged-YAML view whenever a job “disappears” — most phantom failures live in an included file, not the one you edited.
- The free incident assistant can turn an include-resolution error into a likely-cause-and-fix suggestion; more patterns live in the GitLab CI/CD guides.
Related Errors
- Invalid CI config / YAML validation errors — the file itself broke a schema rule, rather than an include failing to resolve.
Included file ... does not have valid YAML syntax!— the include was found, but its contents do not parse; lint the included file directly.job needs ... but it was not added to the pipeline— often appears after an include is fixed but the included jobs are filtered out byrules.
Frequently Asked Questions
Why does include:local work on main but fail on my feature branch?
include:local always reads from the same ref the pipeline runs on. If the template file was only committed to main, a feature-branch pipeline genuinely has no such file. Merge the file into your branch, or switch to a project: include pinned to main.
My include:project file exists — why does GitLab say it does not?
Either the file: path is wrong (it must be absolute from the target repo’s root, with a leading slash), the ref: does not contain that file, or the pipeline identity cannot read the target project. Confirm all three with the repository files API before assuming the file is missing.
What is the difference between does not exist and does not have valid YAML syntax?
does not exist (or is empty or does not exist) means GitLab could not fetch the file at all — a resolution failure. does not have valid YAML syntax means the file was fetched but its contents do not parse. The first is a path/ref problem; the second is a YAML problem inside the included file.
How do I see what my includes actually merged into?
Open the Pipeline Editor’s Full configuration (View merged YAML) tab, or run glab ci lint --include. Both expand every include:, extends:, and anchor so you can see the final resolved config.
Can two files include each other?
No. GitLab refuses circular includes. Restructure so includes form a tree: move the jobs both files share into a separate file that each includes once.
Download the Free 500-Prompt DevOps AI Toolkit
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.