GitLab CI "rules:exists" Not Matching - Glob or Repo-Root Mismatch
rules:exists runs a job only when matching files are present in the repository. It misfires when the glob does not match nested paths, the case is wrong, or the path is assumed relative to a subdirectory.
What this error means
A job guarded by rules:exists never runs even though the file is in the repo, or always runs because the glob is too broad. The pattern and the repo layout do not line up.
# Expected to run when a Dockerfile exists anywhere, but only checks the root:
docker_build:
rules:
- exists:
- Dockerfile # misses services/api/DockerfileCommon causes
Glob does not match nested paths
Dockerfile matches only a root-level file. To match at any depth you need **/Dockerfile. A too-narrow pattern makes the rule never match.
Paths are relative to the repo root
rules:exists evaluates from the repository root, not the job’s working directory. Assuming a subdirectory base makes the path wrong.
Case sensitivity
Glob matching is case-sensitive on Linux runners. dockerfile will not match Dockerfile.
How to fix it
Use a recursive, correctly-cased glob
docker_build:
rules:
- exists:
- '**/Dockerfile'
script: docker build .Anchor paths at the repo root
- Write
existspaths relative to the repository root, not the job CWD. - Match exact case as the file is committed.
- Use
**/to match the file at any directory depth.
How to prevent it
- Prefer
**/namerecursive globs forrules:exists. - Remember
existsis rooted at the repo, regardless of job CWD. - Match committed filename casing exactly on Linux runners.